mirror of
https://github.com/yeicor-3d/yet-another-cad-viewer.git
synced 2025-12-19 22:24:17 +01:00
Merge pull request #245 from yeicor-3d/feature/pyodide-build123d-playground
Add playground functionality: build 3d models by coding in the browser.
This commit is contained in:
14
.github/workflows/build.yml
vendored
14
.github/workflows/build.yml
vendored
@@ -40,9 +40,9 @@ jobs:
|
||||
with:
|
||||
python-version: "3.12"
|
||||
cache: "poetry"
|
||||
- run: "SKIP_BUILD_FRONTEND=true poetry lock"
|
||||
- run: "SKIP_BUILD_FRONTEND=true poetry install"
|
||||
- run: "SKIP_BUILD_FRONTEND=true poetry build"
|
||||
- run: "poetry lock"
|
||||
- run: "poetry install"
|
||||
- run: "poetry build" # Skips building frontend (not using task)
|
||||
|
||||
build-logo:
|
||||
name: "Build logo"
|
||||
@@ -56,8 +56,8 @@ jobs:
|
||||
with:
|
||||
python-version: "3.12"
|
||||
cache: "poetry"
|
||||
- run: "SKIP_BUILD_FRONTEND=true poetry lock"
|
||||
- run: "SKIP_BUILD_FRONTEND=true poetry install"
|
||||
- run: "poetry lock"
|
||||
- run: "poetry install"
|
||||
- run: "poetry run python yacv_server/logo.py"
|
||||
- uses: "actions/upload-artifact@v4"
|
||||
with:
|
||||
@@ -77,8 +77,8 @@ jobs:
|
||||
with:
|
||||
python-version: "3.12"
|
||||
cache: "poetry"
|
||||
- run: "SKIP_BUILD_FRONTEND=true poetry lock"
|
||||
- run: "SKIP_BUILD_FRONTEND=true poetry install"
|
||||
- run: "poetry lock"
|
||||
- run: "poetry install"
|
||||
- run: "YACV_DISABLE_SERVER=true poetry run python example/object.py"
|
||||
- uses: "actions/upload-artifact@v4"
|
||||
with:
|
||||
|
||||
9
.github/workflows/deploy2.yml
vendored
9
.github/workflows/deploy2.yml
vendored
@@ -35,11 +35,7 @@ jobs:
|
||||
- uses: "actions/download-artifact@v4"
|
||||
with: # Downloads all artifacts from the build job
|
||||
path: "./public"
|
||||
- run: | # Merge the subdirectories of public into a single directory
|
||||
for dir in public/*; do
|
||||
mv "$dir/"* public/
|
||||
rmdir "$dir"
|
||||
done
|
||||
merge-multiple: true
|
||||
- uses: "actions/configure-pages@v5"
|
||||
- uses: "actions/upload-pages-artifact@v3"
|
||||
with:
|
||||
@@ -71,5 +67,6 @@ jobs:
|
||||
cache: "poetry"
|
||||
- run: "poetry install"
|
||||
- run: "poetry config pypi-token.pypi ${{ secrets.PYPI_TOKEN }}"
|
||||
- run: "poetry publish --build"
|
||||
- run: "poetry run task build" # This task also builds the frontend (with reduced features for less size)
|
||||
- run: "poetry publish"
|
||||
|
||||
|
||||
@@ -761,6 +761,36 @@ MIT License
|
||||
|
||||
-----------
|
||||
|
||||
The following npm package may be included in this product:
|
||||
|
||||
- pako@2.1.0
|
||||
|
||||
This package contains the following license:
|
||||
|
||||
(The MIT License)
|
||||
|
||||
Copyright (C) 2014-2017 by Vitaly Puzrin and Andrei Tuputcyn
|
||||
|
||||
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.
|
||||
|
||||
-----------
|
||||
|
||||
The following npm package may be included in this product:
|
||||
|
||||
- lie@3.3.0
|
||||
@@ -1129,6 +1159,35 @@ BSD-3-Clause
|
||||
|
||||
-----------
|
||||
|
||||
The following npm package may be included in this product:
|
||||
|
||||
- ws@8.18.3
|
||||
|
||||
This package contains the following license:
|
||||
|
||||
Copyright (c) 2011 Einar Otto Stangvik <einaros@gmail.com>
|
||||
Copyright (c) 2013 Arnout Kazemier and contributors
|
||||
Copyright (c) 2016 Luigi Pinca and contributors
|
||||
|
||||
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.
|
||||
|
||||
-----------
|
||||
|
||||
The following npm package may be included in this product:
|
||||
|
||||
- color-string@1.9.1
|
||||
@@ -1301,6 +1360,42 @@ THE SOFTWARE.
|
||||
|
||||
-----------
|
||||
|
||||
The following npm package may be included in this product:
|
||||
|
||||
- js-base64@3.7.7
|
||||
|
||||
This package contains the following license:
|
||||
|
||||
Copyright (c) 2014, Dan Kogai
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of {{{project}}} nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
-----------
|
||||
|
||||
The following npm package may be included in this product:
|
||||
|
||||
- estree-walker@2.0.2
|
||||
@@ -1537,6 +1632,126 @@ SOFTWARE.
|
||||
|
||||
-----------
|
||||
|
||||
The following npm package may be included in this product:
|
||||
|
||||
- state-local@1.0.7
|
||||
|
||||
This package contains the following license:
|
||||
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020 Suren Atoyan
|
||||
|
||||
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.
|
||||
|
||||
-----------
|
||||
|
||||
The following npm package may be included in this product:
|
||||
|
||||
- vue-demi@0.14.10
|
||||
|
||||
This package contains the following license:
|
||||
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020-present, Anthony Fu
|
||||
|
||||
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.
|
||||
|
||||
-----------
|
||||
|
||||
The following npm package may be included in this product:
|
||||
|
||||
- @monaco-editor/loader@1.5.0
|
||||
|
||||
This package contains the following license:
|
||||
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021 Suren Atoyan
|
||||
|
||||
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.
|
||||
|
||||
-----------
|
||||
|
||||
The following npm package may be included in this product:
|
||||
|
||||
- @guolao/vue-monaco-editor@1.5.5
|
||||
|
||||
This package contains the following license:
|
||||
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 guolao
|
||||
|
||||
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.
|
||||
|
||||
-----------
|
||||
|
||||
The following npm package may be included in this product:
|
||||
|
||||
- @monogrid/gainmap-js@3.1.0
|
||||
@@ -1597,6 +1812,16 @@ SOFTWARE.
|
||||
|
||||
-----------
|
||||
|
||||
The following npm package may be included in this product:
|
||||
|
||||
- pyodide@0.28.0
|
||||
|
||||
This package contains the following license:
|
||||
|
||||
MPL-2.0
|
||||
|
||||
-----------
|
||||
|
||||
The following npm packages may be included in this product:
|
||||
|
||||
- @mdi/js@7.4.47
|
||||
@@ -1771,6 +1996,36 @@ THE SOFTWARE.
|
||||
|
||||
-----------
|
||||
|
||||
The following npm package may be included in this product:
|
||||
|
||||
- monaco-editor@0.52.2
|
||||
|
||||
This package contains the following license:
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 - present Microsoft Corporation
|
||||
|
||||
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.
|
||||
|
||||
-----------
|
||||
|
||||
The following npm package may be included in this product:
|
||||
|
||||
- vuetify@3.9.0
|
||||
|
||||
9
build.py
9
build.py
@@ -1,9 +0,0 @@
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Building the frontend is optional
|
||||
if os.getenv('SKIP_BUILD_FRONTEND') is None and os.path.exists('package.json'):
|
||||
# When building the backend, make sure the frontend is built first
|
||||
subprocess.run(['yarn', 'install'], check=True)
|
||||
subprocess.run(['yarn', 'build', '--outDir', 'yacv_server/frontend'], check=True)
|
||||
@@ -11,7 +11,8 @@ import {NetworkManager, NetworkUpdateEvent, NetworkUpdateEventModel} from "./mis
|
||||
import {SceneMgr} from "./misc/scene";
|
||||
import {Document} from "@gltf-transform/core";
|
||||
import type ModelViewerWrapperT from "./viewer/ModelViewerWrapper.vue";
|
||||
import {mdiPlus} from '@mdi/js'
|
||||
import {mdiCube, mdiPlus, mdiScriptTextPlay} from '@mdi/js'
|
||||
// @ts-expect-error
|
||||
import SvgIcon from '@jamescoyle/vue-icon';
|
||||
|
||||
// NOTE: The ModelViewer library is big (THREE.js), so we split it and import it asynchronously
|
||||
@@ -21,7 +22,7 @@ const ModelViewerWrapper = defineAsyncComponent({
|
||||
delay: 0,
|
||||
});
|
||||
|
||||
let openSidebarsByDefault: Ref<boolean> = ref(window.innerWidth > 1200);
|
||||
let openSidebarsByDefault: Ref<boolean> = ref(window.innerWidth > window.innerHeight);
|
||||
|
||||
const sceneUrl = ref("")
|
||||
const viewer: Ref<InstanceType<typeof ModelViewerWrapperT> | null> = ref(null);
|
||||
@@ -80,17 +81,27 @@ let networkMgr = new NetworkManager();
|
||||
networkMgr.addEventListener('update-early',
|
||||
(e) => viewer.value?.onProgress((e as CustomEvent<Array<any>>).detail.length * 0.01));
|
||||
networkMgr.addEventListener('update', (e) => onModelUpdateRequest(e as NetworkUpdateEvent));
|
||||
let preloadingModels = ref<Array<string>>([]);
|
||||
(async () => { // Start loading all configured models ASAP
|
||||
let sett = await settings();
|
||||
watch(viewer, (newViewer) => {
|
||||
if (newViewer) {
|
||||
newViewer.setPosterText('<tspan x="50%" dy="1.2em">Trying to load' +
|
||||
' models from:</tspan>' + sett.preload.map((url: string) => '<tspan x="50%" dy="1.2em">- ' + url + '</tspan>').join(""));
|
||||
if (sett.preload.length > 0) {
|
||||
watch(viewer, (newViewer) => {
|
||||
if (newViewer) {
|
||||
newViewer.setPosterText('<tspan x="50%" dy="1.2em">Trying to load' +
|
||||
' models from:</tspan>' + sett.preload.map((url: string) => '<tspan x="50%" dy="1.2em">- ' + url + '</tspan>').join(""));
|
||||
}
|
||||
});
|
||||
for (let model of sett.preload) {
|
||||
preloadingModels.value.push(model);
|
||||
let removeFromPreloadingModels = () => {
|
||||
preloadingModels.value = preloadingModels.value.filter((m) => m !== model);
|
||||
};
|
||||
networkMgr.load(model).then(removeFromPreloadingModels).catch((e) => {
|
||||
removeFromPreloadingModels()
|
||||
console.error("Error preloading model", model, e);
|
||||
});
|
||||
}
|
||||
});
|
||||
for (let model of sett.preload) {
|
||||
await networkMgr.load(model);
|
||||
}
|
||||
} // else No preloaded models (useful for playground mode)
|
||||
})();
|
||||
|
||||
async function loadModelManual() {
|
||||
@@ -104,7 +115,28 @@ async function loadModelManual() {
|
||||
|
||||
<!-- The main content of the app is the model-viewer with the SVG "2D" overlay -->
|
||||
<v-main id="main">
|
||||
<model-viewer-wrapper ref="viewer" :src="sceneUrl"/>
|
||||
<model-viewer-wrapper v-if="sceneDocument.getRoot().listMeshes().length > 0" ref="viewer" :src="sceneUrl"/>
|
||||
<!-- A nice no model loaded alternative to avoid breaking model-viewer-wrapper -->
|
||||
<div v-else style="height: 100%; overflow-y: auto">
|
||||
<v-toolbar-title class="text-center ma-16 text-h5">No model loaded</v-toolbar-title>
|
||||
<v-btn @click="() => tools?.openPlayground()" class="mx-auto d-block my-4">
|
||||
<svg-icon :path="mdiScriptTextPlay" type="mdi"/> Open playground...
|
||||
</v-btn>
|
||||
<v-btn @click="networkMgr.load('https://yeicor-3d.github.io/yet-another-cad-viewer/logo.glb')"
|
||||
class="mx-auto d-block my-4">
|
||||
<svg-icon :path="mdiCube" type="mdi"/> Load demo model...
|
||||
</v-btn>
|
||||
<v-btn @click="loadModelManual" class="mx-auto d-block my-4">
|
||||
<svg-icon :path="mdiPlus" type="mdi"/> Load model manually...
|
||||
</v-btn>
|
||||
<span v-if="preloadingModels.length > 0" class="d-block text-center my-16">
|
||||
<span class="d-block text-center text-h6">Still trying to load the following:</span>
|
||||
<span class="d-block text-center" v-for="(model, index) in preloadingModels" :key="index">
|
||||
{{ model }}<span v-if="index < preloadingModels.length - 1">, </span>
|
||||
</span>
|
||||
</span>
|
||||
|
||||
</div>
|
||||
</v-main>
|
||||
|
||||
<!-- The left collapsible sidebar has the list of models -->
|
||||
@@ -117,7 +149,7 @@ async function loadModelManual() {
|
||||
<svg-icon :path="mdiPlus" type="mdi"/>
|
||||
</v-btn>
|
||||
</template>
|
||||
<models ref="models" :viewer="viewer" @remove="onModelRemoveRequest"/>
|
||||
<models ref="models" :viewer="viewer" @remove-model="onModelRemoveRequest"/>
|
||||
</sidebar>
|
||||
|
||||
<!-- The right collapsible sidebar has the list of tools -->
|
||||
@@ -125,7 +157,7 @@ async function loadModelManual() {
|
||||
<template #toolbar>
|
||||
<v-toolbar-title>Tools</v-toolbar-title>
|
||||
</template>
|
||||
<tools ref="tools" :viewer="viewer" @findModel="(name) => models?.findModel(name)"/>
|
||||
<tools ref="tools" :viewer="viewer" @find-model="models?.findModel" @update-model="onModelUpdateRequest"/>
|
||||
</sidebar>
|
||||
|
||||
</v-layout>
|
||||
@@ -135,6 +167,6 @@ async function loadModelManual() {
|
||||
<style>
|
||||
html, body {
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
overflow: hidden !important;
|
||||
}
|
||||
</style>
|
||||
31
frontend/misc/IfNotSmallBuild.vue
Normal file
31
frontend/misc/IfNotSmallBuild.vue
Normal file
@@ -0,0 +1,31 @@
|
||||
<script setup lang="ts">
|
||||
import {mdiLockQuestion} from "@mdi/js";
|
||||
import {VBtn, VTooltip} from "vuetify/lib/components/index.mjs";
|
||||
// @ts-expect-error
|
||||
import SvgIcon from "@jamescoyle/vue-icon";
|
||||
|
||||
// @ts-expect-error
|
||||
let isSmallBuild = typeof __YACV_SMALL_BUILD__ !== 'undefined' && __YACV_SMALL_BUILD__;
|
||||
|
||||
function clickedButton() { // Redirect to the main build
|
||||
window.open("https://yeicor-3d.github.io/yet-another-cad-viewer/" + window.location.search + window.location.hash, '_blank');
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<!-- @ts-ignore-->
|
||||
<!-- Include the children as this is a full build -->
|
||||
<slot v-if="!isSmallBuild"/>
|
||||
<!-- A small info button saying that a feature is missing, and linking to the main build -->
|
||||
<v-btn v-else icon @click="clickedButton" base-color="#a00" style="margin: auto; display: block;">
|
||||
<v-tooltip activator="parent">
|
||||
This feature is not available in the small build.<br/>
|
||||
Click to go to the main build.
|
||||
</v-tooltip>
|
||||
<svg-icon :path="mdiLockQuestion" type="mdi"/>
|
||||
</v-btn>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -2,6 +2,7 @@
|
||||
import {ref} from "vue";
|
||||
import {VBtn, VNavigationDrawer, VToolbar, VToolbarItems} from "vuetify/lib/components/index.mjs";
|
||||
import {mdiChevronLeft, mdiChevronRight, mdiClose} from '@mdi/js'
|
||||
// @ts-expect-error
|
||||
import SvgIcon from '@jamescoyle/vue-icon';
|
||||
|
||||
const props = defineProps<{
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
import {Buffer, Document, Scene, type Transform, WebIO} from "@gltf-transform/core";
|
||||
import {unpartition, mergeDocuments} from "@gltf-transform/functions";
|
||||
import {mergeDocuments, unpartition} from "@gltf-transform/functions";
|
||||
|
||||
let io = new WebIO();
|
||||
export let extrasNameKey = "__yacv_name";
|
||||
export let extrasNameValueHelpers = "__helpers";
|
||||
|
||||
// @ts-expect-error
|
||||
let isSmallBuild = typeof __YACV_SMALL_BUILD__ !== 'undefined' && __YACV_SMALL_BUILD__;
|
||||
|
||||
/**
|
||||
* Loads a GLB model from a URL and adds it to the document or replaces it if the names match.
|
||||
*
|
||||
@@ -27,18 +30,20 @@ export async function mergePartial(url: string, name: string, document: Document
|
||||
try { // Try to load fast if no extensions are used
|
||||
newDoc = await io.readBinary(new Uint8Array(buffer));
|
||||
} catch (e) { // Fallback to wait for download and register big extensions
|
||||
if (e instanceof Error && e.message.toLowerCase().includes("khr_draco_mesh_compression")) {
|
||||
if (!isSmallBuild && e instanceof Error && e.message.toLowerCase().includes("khr_draco_mesh_compression")) {
|
||||
if (alreadyTried["draco"]) throw e; else alreadyTried["draco"] = true;
|
||||
// WARNING: Draco decompression on web is really slow for non-trivial models! (it should work?)
|
||||
let {KHRDracoMeshCompression} = await import("@gltf-transform/extensions")
|
||||
// @ts-expect-error
|
||||
let dracoDecoderWeb = await import("three/examples/jsm/libs/draco/draco_decoder.js");
|
||||
// @ts-expect-error
|
||||
let dracoEncoderWeb = await import("three/examples/jsm/libs/draco/draco_encoder.js");
|
||||
io.registerExtensions([KHRDracoMeshCompression])
|
||||
.registerDependencies({
|
||||
'draco3d.decoder': await dracoDecoderWeb.default({}),
|
||||
'draco3d.encoder': await dracoEncoderWeb.default({})
|
||||
});
|
||||
} else if (e instanceof Error && e.message.toLowerCase().includes("ext_texture_webp")) {
|
||||
} else if (!isSmallBuild && e instanceof Error && e.message.toLowerCase().includes("ext_texture_webp")) {
|
||||
if (alreadyTried["webp"]) throw e; else alreadyTried["webp"] = true;
|
||||
let {EXTTextureWebP} = await import("@gltf-transform/extensions")
|
||||
io.registerExtensions([EXTTextureWebP]);
|
||||
|
||||
@@ -82,7 +82,7 @@ export function newAxes(doc: Document, size: Vector3, transform: Matrix4) {
|
||||
* The grid is built as a box of triangles (representing lines) looking to the inside of the box.
|
||||
* This ensures that only the back of the grid is always visible, regardless of the camera position.
|
||||
*/
|
||||
export async function newGridBox(doc: Document, size: Vector3, baseTransform: Matrix4, divisions = 10) {
|
||||
export function newGridBox(doc: Document, size: Vector3, baseTransform: Matrix4, divisions = 10) {
|
||||
// Create transformed positions for the inner faces of the box
|
||||
let allPositions: number[] = [];
|
||||
let allIndices: number[] = [];
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {type Ref} from 'vue';
|
||||
import {Document} from '@gltf-transform/core';
|
||||
import {Buffer, Document, Scene} from '@gltf-transform/core';
|
||||
import {extrasNameKey, extrasNameValueHelpers, mergeFinalize, mergePartial, removeModel, toBuffer} from "./gltf";
|
||||
import {newAxes, newGridBox} from "./helpers";
|
||||
import {Vector3} from "three/src/math/Vector3.js"
|
||||
@@ -80,7 +80,19 @@ export class SceneMgr {
|
||||
|
||||
private static async reloadHelpers(sceneUrl: Ref<string>, document: Document, reloadScene: boolean): Promise<Document> {
|
||||
let bb = SceneMgr.getBoundingBox(document);
|
||||
if (!bb) return document;
|
||||
if (!bb) return document; // Empty document, no helpers to show
|
||||
|
||||
// If only the helpers remain, go back to the empty scene
|
||||
let noOtherModels = true;
|
||||
for (let elem of document.getGraph().listEdges().map(e => e.getChild())) {
|
||||
if (elem.getExtras() && !(elem instanceof Scene) && !(elem instanceof Buffer) &&
|
||||
elem.getExtras()[extrasNameKey] !== extrasNameValueHelpers) {
|
||||
// There are other elements in the document, so we can show the helpers
|
||||
noOtherModels = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (noOtherModels) return await removeModel(extrasNameValueHelpers, document);
|
||||
|
||||
// Create the helper axes and grid box
|
||||
let helpersDoc = new Document();
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
// These are the default values for the settings, which are overridden below
|
||||
import {ungzip} from "pako";
|
||||
import {b66Decode} from "../tools/b66.ts";
|
||||
|
||||
let settingsCache: any = null;
|
||||
|
||||
export async function settings() {
|
||||
@@ -38,18 +41,50 @@ export async function settings() {
|
||||
"12NgAAAAAgAB4iG8MwAAAABJRU5ErkJggg==" :
|
||||
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEW6urpaLVq8AAAACklEQVQI" +
|
||||
"12NgAAAAAgAB4iG8MwAAAABJRU5ErkJggg=="),
|
||||
|
||||
// Playground settings
|
||||
pg_code: "", // Automatically loaded and executed code for the playground
|
||||
pg_code_url: "", // URL to load the code from (overrides pg_code)
|
||||
pg_opacity_loading: -1, // Opacity of the code during first load and run (< 0 is 0.0 if preload and 0.9 if not)
|
||||
pg_opacity_loaded: 0.9, // Opacity of the code after it has been run for the first time
|
||||
};
|
||||
|
||||
// Auto-override any settings from the URL
|
||||
// Auto-override any settings from the URL (either GET parameters or hash)
|
||||
const url = new URL(window.location.href);
|
||||
url.searchParams.forEach((value, key) => {
|
||||
if (key in settings) (settings as any)[key] = parseSetting(key, value, settings);
|
||||
})
|
||||
if (url.hash.length > 0) { // Hash has bigger limits as it is not sent to the server
|
||||
const hash = url.hash.slice(1);
|
||||
const hashParams = new URLSearchParams(hash);
|
||||
hashParams.forEach((value, key) => {
|
||||
if (key in settings) (settings as any)[key] = parseSetting(key, value, settings);
|
||||
});
|
||||
}
|
||||
|
||||
// Grab the code from the URL if it is set
|
||||
if (settings.pg_code_url.length > 0) {
|
||||
// If the code URL is set, override the code
|
||||
try {
|
||||
const response = await fetch(settings.pg_code_url);
|
||||
if (response.ok) {
|
||||
settings.pg_code = await response.text();
|
||||
} else {
|
||||
console.warn("Failed to load code from URL:", settings.pg_code_url);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching code from URL:", settings.pg_code_url, error);
|
||||
}
|
||||
}
|
||||
|
||||
// Get the default preload URL if not overridden (requires a fetch that is avoided if possible)
|
||||
for (let i = 0; i < settings.preload.length; i++) {
|
||||
let url = settings.preload[i];
|
||||
if (url === '<auto>') {
|
||||
if (settings.pg_code != "") { // <auto> means no preload URL if code is set
|
||||
settings.preload = settings.preload.slice(0, i).concat(settings.preload.slice(i + 1));
|
||||
continue; // Skip this preload URL
|
||||
}
|
||||
const possibleBackend = new URL("./?api_updates=true", window.location.href)
|
||||
await fetch(possibleBackend, {method: "HEAD"}).then((response) => {
|
||||
if (response.ok && response.headers.get("Content-Type") === "text/event-stream") {
|
||||
@@ -63,6 +98,20 @@ export async function settings() {
|
||||
}
|
||||
settings.preload[i] = url;
|
||||
}
|
||||
|
||||
// Auto-decompress the code and other playground settings
|
||||
if (settings.pg_code.length > 0) {
|
||||
try {
|
||||
settings.pg_code = ungzip(b66Decode(settings.pg_code), {to: 'string'});
|
||||
} catch (error) {
|
||||
console.warn("Failed to decompress code (assuming raw code):", error);
|
||||
}
|
||||
if (settings.pg_opacity_loading < 0) {
|
||||
// If the opacity is not set, use 0.0 if preload is set, otherwise 0.9
|
||||
settings.pg_opacity_loading = settings.preload.length > 0 ? 0.0 : 0.9;
|
||||
}
|
||||
}
|
||||
|
||||
settingsCache = settings;
|
||||
return settings;
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import {
|
||||
mdiVectorLine,
|
||||
mdiVectorRectangle
|
||||
} from '@mdi/js'
|
||||
// @ts-expect-error
|
||||
import SvgIcon from '@jamescoyle/vue-icon';
|
||||
import {BackSide, FrontSide} from "three/src/constants.js";
|
||||
import {Box3} from "three/src/math/Box3.js";
|
||||
@@ -34,6 +35,8 @@ import {Vector3} from "three/src/math/Vector3.js";
|
||||
import type {MObject3D} from "../tools/Selection.vue";
|
||||
import {toLineSegments} from "../misc/lines.js";
|
||||
import {settings} from "../misc/settings.js"
|
||||
import {currentSceneRotation} from "../viewer/lighting.ts";
|
||||
import {Matrix4} from "three/src/math/Matrix4.js";
|
||||
|
||||
const props = defineProps<{
|
||||
meshes: Array<Mesh>,
|
||||
@@ -115,7 +118,8 @@ function onWireframeChange(newWireframe: boolean) {
|
||||
if (!scene || !sceneModel) return;
|
||||
sceneModel.traverse((child: MObject3D) => {
|
||||
if (child.userData[extrasNameKey] === modelName) {
|
||||
if (child.material && child.material.wireframe !== newWireframe) {
|
||||
let childIsFace = child.type == 'Mesh' || child.type == 'SkinnedMesh'
|
||||
if (child.material && child.material.wireframe !== newWireframe && childIsFace) {
|
||||
child.material.wireframe = newWireframe;
|
||||
child.material.needsUpdate = true;
|
||||
}
|
||||
@@ -153,10 +157,11 @@ function onClipPlanesChange() {
|
||||
let offsetX = bbox.min.x + clipPlaneX.value * (bbox.max.x - bbox.min.x);
|
||||
let offsetY = bbox.min.y + clipPlaneY.value * (bbox.max.y - bbox.min.y);
|
||||
let offsetZ = bbox.min.z + (1 - clipPlaneZ.value) * (bbox.max.z - bbox.min.z);
|
||||
let rotSceneMatrix = new Matrix4().makeRotationY(currentSceneRotation);
|
||||
let planes = [
|
||||
new Plane(new Vector3(-1, 0, 0), offsetX),
|
||||
new Plane(new Vector3(0, -1, 0), offsetY),
|
||||
new Plane(new Vector3(0, 0, 1), -offsetZ),
|
||||
new Plane(new Vector3(-1, 0, 0), offsetX).applyMatrix4(rotSceneMatrix),
|
||||
new Plane(new Vector3(0, -1, 0), offsetY).applyMatrix4(rotSceneMatrix),
|
||||
new Plane(new Vector3(0, 0, 1), -offsetZ).applyMatrix4(rotSceneMatrix),
|
||||
];
|
||||
if (clipPlaneSwappedX.value) planes[0].negate();
|
||||
if (clipPlaneSwappedY.value) planes[1].negate();
|
||||
@@ -227,9 +232,10 @@ function onEdgeWidthChange(newEdgeWidth: number) {
|
||||
line.userData.niceLine = line2;
|
||||
// line.parent!.remove(line); // Keep it for better raycast and selection!
|
||||
line2.userData.noHit = true;
|
||||
line2.visible = enabledFeatures.value.includes(1);
|
||||
edgeWidthChangeCleanup.push(() => {
|
||||
line2.parent!.remove(line2);
|
||||
line.visible = true;
|
||||
line.visible = enabledFeatures.value.includes(1);
|
||||
props.viewer!!.onElemReady((elem) => {
|
||||
elem.removeEventListener('resize', () => resizeListener(elem));
|
||||
});
|
||||
|
||||
@@ -7,7 +7,7 @@ import Model from "./Model.vue";
|
||||
import {inject, ref, type Ref} from "vue";
|
||||
|
||||
const props = defineProps<{ viewer: InstanceType<typeof ModelViewerWrapper> | null }>();
|
||||
const emit = defineEmits<{ remove: [string] }>()
|
||||
const emit = defineEmits<{ removeModel: [string] }>()
|
||||
|
||||
let {sceneDocument} = inject<{ sceneDocument: Ref<Document> }>('sceneDocument')!!;
|
||||
|
||||
@@ -32,7 +32,7 @@ function meshName(mesh: Mesh) {
|
||||
}
|
||||
|
||||
function onRemove(mesh: Mesh) {
|
||||
emit('remove', meshName(mesh))
|
||||
emit('removeModel', meshName(mesh))
|
||||
}
|
||||
|
||||
function findModel(name: string) {
|
||||
|
||||
5
frontend/shims.d.ts
vendored
5
frontend/shims.d.ts
vendored
@@ -1,5 +0,0 @@
|
||||
// Avoids typescript error when importing some files
|
||||
declare module '@jamescoyle/vue-icon'
|
||||
declare module 'three-orientation-gizmo/src/OrientationGizmo'
|
||||
declare module 'three/examples/jsm/libs/draco/draco_decoder.js'
|
||||
declare module 'three/examples/jsm/libs/draco/draco_encoder.js'
|
||||
@@ -1,12 +1,15 @@
|
||||
<script lang="ts" setup>
|
||||
import {onMounted, onUpdated, ref} from "vue";
|
||||
import type {ModelScene} from "@google/model-viewer/lib/three-components/ModelScene";
|
||||
// @ts-expect-error
|
||||
import * as OrientationGizmoRaw from "three-orientation-gizmo/src/OrientationGizmo";
|
||||
import type ModelViewerWrapper from "../viewer/ModelViewerWrapper.vue";
|
||||
import {currentSceneRotation} from "../viewer/lighting.ts";
|
||||
|
||||
// Optimized minimal dependencies from three
|
||||
import {Vector3} from "three/src/math/Vector3.js";
|
||||
import {Matrix4} from "three/src/math/Matrix4.js";
|
||||
import type ModelViewerWrapper from "../viewer/ModelViewerWrapper.vue";
|
||||
import {Euler} from "three/src/math/Euler.js";
|
||||
|
||||
(globalThis as any).THREE = {Vector3, Matrix4} as any // HACK: Required for the gizmo to work
|
||||
|
||||
@@ -48,7 +51,7 @@ function createGizmo(expectedParent: HTMLElement, scene: ModelScene): HTMLElemen
|
||||
axis.direction.y = -axis.direction.y;
|
||||
axis.direction.z = -axis.direction.z;
|
||||
}
|
||||
wantedTheta = Math.atan2(axis.direction.x, axis.direction.z);
|
||||
wantedTheta = Math.atan2(axis.direction.x, axis.direction.z) + currentSceneRotation;
|
||||
wantedPhi = Math.asin(-axis.direction.y) + Math.PI / 2;
|
||||
attempt++;
|
||||
}
|
||||
@@ -66,7 +69,12 @@ let gizmo: HTMLElement & { update: () => void }
|
||||
|
||||
function updateGizmo() {
|
||||
if (gizmo.isConnected) {
|
||||
// HACK: Update camera temporarily to match skybox rotation before updating the gizmo and go back
|
||||
let prevRot = ((gizmo as any).camera).rotation.clone() as Euler;
|
||||
let thetaMat = new Matrix4().makeRotationY(-currentSceneRotation);
|
||||
((gizmo as any).camera).rotation.setFromRotationMatrix(thetaMat.multiply(new Matrix4().makeRotationFromEuler(prevRot)));
|
||||
gizmo.update();
|
||||
((gizmo as any).camera).rotation.set(prevRot.x, prevRot.y, prevRot.z);
|
||||
requestIdleCallback(updateGizmo, {timeout: 250});
|
||||
}
|
||||
}
|
||||
|
||||
341
frontend/tools/PlaygroundDialogContent.vue
Normal file
341
frontend/tools/PlaygroundDialogContent.vue
Normal file
@@ -0,0 +1,341 @@
|
||||
<script setup lang="ts">
|
||||
import {setupMonaco} from "./monaco.ts";
|
||||
import {VueMonacoEditor} from '@guolao/vue-monaco-editor'
|
||||
import {nextTick, onMounted, ref, shallowRef} from "vue";
|
||||
import Loading from "../misc/Loading.vue";
|
||||
import {newPyodideWorker} from "./pyodide-worker-api.ts";
|
||||
import {mdiCircleOpacity, mdiClose, mdiContentSave, mdiFolderOpen, mdiPlay, mdiReload, mdiShare} from "@mdi/js";
|
||||
import {VBtn, VCard, VCardText, VSlider, VSpacer, VToolbar, VToolbarTitle, VTooltip} from "vuetify/components";
|
||||
// @ts-expect-error
|
||||
import SvgIcon from '@jamescoyle/vue-icon';
|
||||
import {version as pyodideVersion} from "pyodide";
|
||||
import {gzip} from 'pako';
|
||||
import {b66Encode} from "./b66.ts";
|
||||
import {Base64} from 'js-base64'; // More compatible with binary data from python...
|
||||
import {NetworkUpdateEvent, NetworkUpdateEventModel} from "../misc/network.ts";
|
||||
import {settings} from "../misc/settings.ts";
|
||||
|
||||
const props = defineProps<{ initialCode: string }>();
|
||||
const emit = defineEmits<{ close: [], updateModel: [NetworkUpdateEvent] }>()
|
||||
|
||||
// ============ LOAD MONACO EDITOR ============
|
||||
setupMonaco() // Must be called before using the editor
|
||||
|
||||
const code = ref(props.initialCode); // TODO: Default code as input (and autorun!)
|
||||
const outputText = ref(``);
|
||||
|
||||
function output(text: string) {
|
||||
outputText.value += text; // Append to output
|
||||
// Avoid too much output, keep it reasonable
|
||||
let max_output = 10000; // 10k characters
|
||||
if (outputText.value.length > max_output) {
|
||||
outputText.value = outputText.value.slice(-max_output); // Keep only the last 10k characters
|
||||
}
|
||||
console.log(text); // Also log to console
|
||||
nextTick(() => { // Scroll to bottom
|
||||
const consoleElement = document.querySelector('.playground-console');
|
||||
if (consoleElement) {
|
||||
consoleElement.scrollTop = consoleElement.scrollHeight;
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const MONACO_EDITOR_OPTIONS = {
|
||||
automaticLayout: true,
|
||||
formatOnType: true,
|
||||
formatOnPaste: true,
|
||||
}
|
||||
|
||||
const editorTheme = window.matchMedia("(prefers-color-scheme: dark)").matches ? `vs-dark` : `vs`
|
||||
const editor = shallowRef()
|
||||
const handleMount = (editorInstance: typeof VueMonacoEditor) => (editor.value = editorInstance)
|
||||
const opacity = ref(0.9); // Opacity for the editor
|
||||
|
||||
// ============ LOAD PYODIDE (ASYNC) ============
|
||||
let pyodideWorker: ReturnType<typeof newPyodideWorker> | null = (import.meta as any).hot?.data?.pyodideWorker || null;
|
||||
const running = ref(true);
|
||||
|
||||
async function setupPyodide() {
|
||||
running.value = true;
|
||||
if (opacity.value == 0.0) opacity.value = 0.9; // User doesn't know how to show code again, reset after reopening
|
||||
if (pyodideWorker === null) {
|
||||
output("Creating new Pyodide worker...\n");
|
||||
pyodideWorker = newPyodideWorker({
|
||||
indexURL: `https://cdn.jsdelivr.net/pyodide/v${pyodideVersion}/full/`, // FIXME: Local deployment?
|
||||
packages: ["micropip", "sqlite3"], // Faster load if done here
|
||||
});
|
||||
if ((import.meta as any).hot) (import.meta as any).hot.data.pyodideWorker = pyodideWorker
|
||||
} else {
|
||||
output("Reusing existing Pyodide instance...\n");
|
||||
}
|
||||
output("Preloading packages...\n");
|
||||
await pyodideWorker.asyncRun(`import micropip, asyncio
|
||||
micropip.set_index_urls(["https://yeicor.github.io/OCP.wasm", "https://pypi.org/simple"])
|
||||
await (micropip.install("lib3mf"))
|
||||
micropip.add_mock_package("py-lib3mf", "2.4.1", modules={"py_lib3mf": 'from lib3mf import *'})
|
||||
await (micropip.install(["https://files.pythonhosted.org/packages/67/25/80be117f39ff5652a4fdbd761b061123c5425e379f4b0a5ece4353215d86/yacv_server-0.10.0a4-py3-none-any.whl"]))
|
||||
from yacv_server import *
|
||||
micropip.add_mock_package("ocp-vscode", "2.8.9", modules={"ocp_vscode": 'from yacv_server import *'})`, output, output); // Also import yacv_server and mock ocp_vscode here for faster custom code execution
|
||||
running.value = false; // Indicate that Pyodide is ready
|
||||
output("Pyodide worker initialized.\n");
|
||||
}
|
||||
|
||||
async function runCode() {
|
||||
if (pyodideWorker === null) {
|
||||
output("Pyodide worker is not initialized. Please wait...\n");
|
||||
return;
|
||||
}
|
||||
if (running.value) {
|
||||
output("Pyodide is already running. Please wait...\n");
|
||||
return;
|
||||
}
|
||||
output("Running code...\n");
|
||||
try {
|
||||
running.value = true;
|
||||
await pyodideWorker.asyncRun(code.value, output, (msg: string) => {
|
||||
// Detect models printed to console (since http server is not available in pyodide)
|
||||
if (msg.startsWith(yacvServerModelPrefix)) {
|
||||
const modelData = msg.slice(yacvServerModelPrefix.length);
|
||||
onModelData(modelData);
|
||||
} else {
|
||||
output(msg); // Print other messages directly
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
output(`Error running initial code: ${e}\n`);
|
||||
} finally {
|
||||
running.value = false; // Indicate that Pyodide is ready
|
||||
}
|
||||
}
|
||||
|
||||
const yacvServerModelPrefix = "yacv_server://model/";
|
||||
|
||||
function onModelData(modelData: string) {
|
||||
output(`Model data detected... ${modelData.length}B\n`);
|
||||
// Decode the model data and emit the event for the interface to handle
|
||||
// - Start by finding the end of the initial json object by looking for brackets.
|
||||
let i = 0;
|
||||
let openBrackets = 0;
|
||||
for (; i < modelData.length; i++) {
|
||||
if (modelData[i] === '{') openBrackets++;
|
||||
else if (modelData[i] === '}') openBrackets--;
|
||||
if (openBrackets === 0) break; // Found the end of the JSON object
|
||||
}
|
||||
if (openBrackets !== 0) throw `Error: Invalid model data received: ${modelData}\n`
|
||||
const jsonData = modelData.slice(0, i + 1); // Extract the JSON part and parse it into the proper class
|
||||
let modelMetadataRaw = JSON.parse(jsonData);
|
||||
const modelMetadata: any = new NetworkUpdateEventModel(modelMetadataRaw.name, "", modelMetadataRaw.hash, modelMetadataRaw.is_remove)
|
||||
// console.debug(`Model metadata:`, modelMetadata);
|
||||
output(`Model metadata: ${JSON.stringify(modelMetadata)}\n`);
|
||||
// - Now decode the rest of the model data which is a single base64 encoded glb file (or an empty string)
|
||||
if (!modelMetadata.isRemove) {
|
||||
const binaryData = Base64.toUint8Array(modelData.slice(i + 1)); // Extract the base64 part
|
||||
console.assert(binaryData.slice(0, 4).toString() == "103,108,84,70", // Ugly...
|
||||
"Invalid GLTF binary data received: " + binaryData.slice(0, 4).toString());
|
||||
// - Create a Blob from the binary data to be used as a URL
|
||||
const blob = new Blob([binaryData], {type: 'model/gltf-binary'});
|
||||
modelMetadata.url = URL.createObjectURL(blob); // Set the hacked URL in the model metadata
|
||||
}
|
||||
// - Emit the event with the model metadata and URL
|
||||
let networkUpdateEvent = new NetworkUpdateEvent([modelMetadata], () => {
|
||||
});
|
||||
emit('updateModel', networkUpdateEvent);
|
||||
}
|
||||
|
||||
function resetWorker() {
|
||||
if (pyodideWorker) {
|
||||
pyodideWorker.terminate(); // Terminate existing worker
|
||||
pyodideWorker = null; // Reset worker reference
|
||||
}
|
||||
outputText.value = ``; // Clear output text
|
||||
setupPyodide(); // Reinitialize Pyodide
|
||||
}
|
||||
|
||||
function shareLink() {
|
||||
const baseUrl = window.location
|
||||
const urlParams = new URLSearchParams(baseUrl.hash.slice(1)); // Keep all previous URL parameters
|
||||
urlParams.set('pg_code', b66Encode(gzip(code.value, {level: 9}))); // Compress and encode the code
|
||||
const shareUrl = `${baseUrl.origin}${baseUrl.pathname}${baseUrl.search}#${urlParams.toString()}`; // Prefer hash to GET (bigger limits)
|
||||
output(`Share link ready: ${shareUrl}\n`)
|
||||
if (!navigator.clipboard) {
|
||||
output("Clipboard API not available. Please copy the link manually.\n");
|
||||
return;
|
||||
} else {
|
||||
navigator.clipboard.writeText(shareUrl)
|
||||
.then(() => output("Link copied to clipboard!\n"))
|
||||
.catch(err => output(`Failed to copy link: ${err}\n`));
|
||||
}
|
||||
}
|
||||
|
||||
function saveSnapshot() {
|
||||
throw new Error("Not implemented yet!"); // TODO: Implement snapshot saving
|
||||
}
|
||||
|
||||
function loadSnapshot() {
|
||||
throw new Error("Not implemented yet!"); // TODO: Implement snapshot loading
|
||||
}
|
||||
|
||||
const reused = (import.meta as any).hot?.data?.pyodideWorker !== undefined;
|
||||
(async () => {
|
||||
const sett = await settings()
|
||||
if (!reused) opacity.value = sett.pg_opacity_loading
|
||||
await setupPyodide()
|
||||
if (props.initialCode != "" && !reused) await runCode();
|
||||
if (!reused) opacity.value = sett.pg_opacity_loaded
|
||||
})()
|
||||
|
||||
// Add keyboard shortcuts
|
||||
const editorRef = ref<HTMLElement | null>(null);
|
||||
onMounted(() => {
|
||||
if (editorRef.value) {
|
||||
console.log(editorRef.value)
|
||||
editorRef.value.addEventListener('keydown', (event: Event) => {
|
||||
if (!(event instanceof KeyboardEvent)) return; // Ensure event is a KeyboardEvent
|
||||
if (event.key === 'Enter' && event.ctrlKey) {
|
||||
event.preventDefault(); // Prevent default behavior of Enter key
|
||||
runCode(); // Run code on Ctrl+Enter
|
||||
} else if (event.key === 'Escape') {
|
||||
emit('close'); // Close on Escape key
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<v-card class="popup-card"
|
||||
:style="opacity == 0 ? `position: absolute; top: calc(-50vh + 24px); width: calc(100vw - 64px);` : ``">
|
||||
<v-toolbar class="popup">
|
||||
<v-toolbar-title style="flex: 0 1 auto">Playground</v-toolbar-title>
|
||||
<v-spacer></v-spacer>
|
||||
|
||||
<span style="display: inline-flex; margin-right: 16px;">
|
||||
<svg-icon :path="mdiCircleOpacity" type="mdi" style="height: 32px"></svg-icon>
|
||||
<v-slider v-model="opacity" :max="1" :min="0" :step="0.1"
|
||||
style="width: 100px; height: 32px">
|
||||
</v-slider>
|
||||
<v-tooltip activator="parent"
|
||||
location="bottom">Opacity of the editor (0 = hidden, 1 = fully visible)</v-tooltip>
|
||||
</span>
|
||||
|
||||
<span style="margin-right: -8px;"><!-- This span is only needed to force tooltip to work while button is disabled -->
|
||||
<v-btn icon disabled @click="saveSnapshot()">
|
||||
<svg-icon :path="mdiContentSave" type="mdi"/>
|
||||
</v-btn>
|
||||
<v-tooltip activator="parent"
|
||||
location="bottom">Save current state to a snapshot for fast startup (WIP)</v-tooltip>
|
||||
</span>
|
||||
<span style="margin-left: -8px"><!-- This span is only needed to force tooltip to work while button is disabled -->
|
||||
<v-btn icon disabled @click="loadSnapshot()">
|
||||
<svg-icon :path="mdiFolderOpen" type="mdi"/>
|
||||
</v-btn>
|
||||
<v-tooltip activator="parent" location="bottom">Load snapshot for fast startup (WIP)</v-tooltip>
|
||||
</span>
|
||||
|
||||
<v-btn icon @click="resetWorker()">
|
||||
<svg-icon :path="mdiReload" type="mdi"/>
|
||||
<v-tooltip activator="parent" location="bottom">Reset Pyodide worker (this forgets all previous state and will
|
||||
take a little while)
|
||||
</v-tooltip>
|
||||
</v-btn>
|
||||
|
||||
<v-btn icon @click="runCode()" :disabled="running">
|
||||
<svg-icon :path="mdiPlay" type="mdi"/>
|
||||
<Loading v-if="running" style="position: absolute; top: -16%; left: -16%"/><!-- Ugly positioning -->
|
||||
<v-tooltip activator="parent" location="bottom">Run code</v-tooltip>
|
||||
</v-btn>
|
||||
|
||||
<v-btn icon @click="shareLink()">
|
||||
<svg-icon :path="mdiShare" type="mdi"/>
|
||||
<v-tooltip activator="parent" location="bottom">Share link that auto-runs the code</v-tooltip>
|
||||
</v-btn>
|
||||
|
||||
<v-btn icon @click="emit('close')">
|
||||
<svg-icon :path="mdiClose" type="mdi"/>
|
||||
<v-tooltip activator="parent" location="bottom">Close (Pyodide remains loaded)</v-tooltip>
|
||||
</v-btn>
|
||||
</v-toolbar>
|
||||
<v-card-text class="popup-card-text" :style="opacity == 0 ? `display: none` : ``">
|
||||
<!-- Only show content if opacity is greater than 0 -->
|
||||
<div class="playground-container">
|
||||
<div class="playground-editor" ref="editorRef">
|
||||
<VueMonacoEditor v-model:value="code" :theme="editorTheme" :options="MONACO_EDITOR_OPTIONS"
|
||||
language="python" @mount="handleMount"/>
|
||||
</div>
|
||||
<div class="playground-console">
|
||||
<h3>Console Output</h3>
|
||||
<pre>{{ outputText }}</pre> <!-- Placeholder for console output -->
|
||||
<Loading v-if="running"/>
|
||||
</div>
|
||||
</div>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.popup-card {
|
||||
background-color: #00000000; /* Transparent background */
|
||||
}
|
||||
|
||||
.v-toolbar.popup > * {
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.popup-card-text {
|
||||
background-color: #1e1e1e; /* Matches the Monaco editor background */
|
||||
opacity: v-bind(opacity);
|
||||
}
|
||||
|
||||
.playground-container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.playground-editor {
|
||||
flex: 1;
|
||||
height: calc(100vh - 150px);
|
||||
}
|
||||
|
||||
.playground-console {
|
||||
flex: 0.5;
|
||||
padding: 10px;
|
||||
overflow-y: auto;
|
||||
min-width: 100px;
|
||||
height: calc(100vh - 150px);
|
||||
}
|
||||
|
||||
.playground-console pre {
|
||||
margin: 0;
|
||||
white-space: pre-wrap;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
@media (min-height: 100vw) {
|
||||
/* Adjust layout for vertical space */
|
||||
.playground-container {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.playground-editor {
|
||||
flex: 1;
|
||||
min-height: 60vh;
|
||||
}
|
||||
|
||||
.playground-editor > * {
|
||||
min-height: 60vh;
|
||||
}
|
||||
|
||||
.playground-console {
|
||||
max-height: calc(40vh - 150px);
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: Adjust more colors on bright mode */
|
||||
</style>
|
||||
|
||||
<style>
|
||||
/* https://stackoverflow.com/questions/47017753/monaco-editor-dynamically-resizable/71876526#71876526 */
|
||||
.monaco-editor {
|
||||
position: absolute !important;
|
||||
}
|
||||
</style>
|
||||
@@ -1,6 +1,7 @@
|
||||
<script lang="ts" setup>
|
||||
import {inject, ref, type ShallowRef, watch} from "vue";
|
||||
import {VBtn, VSelect, VTooltip} from "vuetify/lib/components/index.mjs";
|
||||
// @ts-expect-error
|
||||
import SvgIcon from '@jamescoyle/vue-icon';
|
||||
import type {ModelViewerElement} from '@google/model-viewer';
|
||||
import type {ModelScene} from "@google/model-viewer/lib/three-components/ModelScene";
|
||||
@@ -28,7 +29,7 @@ let emit = defineEmits<{ findModel: [string] }>();
|
||||
let {setDisableTap} = inject<{ setDisableTap: (arg0: boolean) => void }>('disableTap')!!;
|
||||
let selectionEnabled = ref(false);
|
||||
let selected = defineModel<Array<SelectionInfo>>({default: []});
|
||||
let highlightNextSelection = ref([false, false]); // Second is whether selection was enabled before
|
||||
let openNextSelection = ref([false, false]); // Second is whether selection was enabled before
|
||||
let showBoundingBox = ref<Boolean>(false); // Enabled automatically on start
|
||||
let showDistances = ref<Boolean>(true);
|
||||
|
||||
@@ -149,7 +150,7 @@ let mouseUpListener = (event: MouseEvent) => {
|
||||
// Return the best hit
|
||||
[0] as Intersection<MObject3D> | undefined;
|
||||
|
||||
if (!highlightNextSelection.value[0]) {
|
||||
if (!openNextSelection.value[0]) {
|
||||
// If we are selecting, toggle the selection or deselect all if no hit
|
||||
let selInfo: SelectionInfo | null = null;
|
||||
if (hit) selInfo = hitToSelectionInfo(hit);
|
||||
@@ -171,7 +172,7 @@ let mouseUpListener = (event: MouseEvent) => {
|
||||
// Otherwise, highlight the model that owns the hit
|
||||
emit('findModel', hit.object.userData[extrasNameKey])
|
||||
// And reset the selection mode
|
||||
toggleHighlightNextSelection()
|
||||
toggleOpenNextSelection()
|
||||
}
|
||||
scene.queueRender() // Force rerender of model-viewer
|
||||
}
|
||||
@@ -209,17 +210,17 @@ function toggleSelection() {
|
||||
setDisableTap(selectionEnabled.value);
|
||||
}
|
||||
|
||||
function toggleHighlightNextSelection() {
|
||||
highlightNextSelection.value = [
|
||||
!highlightNextSelection.value[0],
|
||||
highlightNextSelection.value[0] ? highlightNextSelection.value[1] : selectionEnabled.value
|
||||
function toggleOpenNextSelection() {
|
||||
openNextSelection.value = [
|
||||
!openNextSelection.value[0],
|
||||
openNextSelection.value[0] ? openNextSelection.value[1] : selectionEnabled.value
|
||||
];
|
||||
if (highlightNextSelection.value[0]) {
|
||||
if (openNextSelection.value[0]) {
|
||||
// Reuse selection code to identify the model
|
||||
if (!selectionEnabled.value) toggleSelection()
|
||||
} else {
|
||||
if (selectionEnabled.value !== highlightNextSelection.value[1]) toggleSelection()
|
||||
highlightNextSelection.value = [false, false];
|
||||
if (selectionEnabled.value !== openNextSelection.value[1]) toggleSelection()
|
||||
openNextSelection.value = [false, false];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -427,6 +428,10 @@ defineExpose({deselect, updateBoundingBox, updateDistances});
|
||||
|
||||
// Add keyboard shortcuts
|
||||
window.addEventListener('keydown', (event) => {
|
||||
if ((event.target as any)?.tagName && ((event.target as any).tagName === 'INPUT' || (event.target as any).tagName === 'TEXTAREA')) {
|
||||
// Ignore key events when an input is focused, except for text inputs
|
||||
return;
|
||||
}
|
||||
if (event.key === 's') {
|
||||
if (selectFilter.value == 'Any (S)') toggleSelection();
|
||||
else {
|
||||
@@ -455,8 +460,8 @@ window.addEventListener('keydown', (event) => {
|
||||
toggleShowBoundingBox();
|
||||
} else if (event.key === 'd') {
|
||||
toggleShowDistances();
|
||||
} else if (event.key === 'h') {
|
||||
toggleHighlightNextSelection();
|
||||
} else if (event.key === 'o') {
|
||||
toggleOpenNextSelection();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -474,8 +479,8 @@ window.addEventListener('keydown', (event) => {
|
||||
variant="underlined"/>
|
||||
</template>
|
||||
</v-tooltip>
|
||||
<v-btn :color="highlightNextSelection[0] ? 'surface-light' : ''" icon @click="toggleHighlightNextSelection">
|
||||
<v-tooltip activator="parent">(H)ighlight the next clicked element in the models list</v-tooltip>
|
||||
<v-btn :color="openNextSelection[0] ? 'surface-light' : ''" icon @click="toggleOpenNextSelection">
|
||||
<v-tooltip activator="parent">(O)pen the next clicked element in the models list</v-tooltip>
|
||||
<svg-icon :path="mdiFeatureSearch" type="mdi"/>
|
||||
</v-btn>
|
||||
<v-btn :color="showBoundingBox ? 'surface-light' : ''" icon @click="toggleShowBoundingBox">
|
||||
|
||||
@@ -13,13 +13,26 @@ import {
|
||||
import OrientationGizmo from "./OrientationGizmo.vue";
|
||||
import type {PerspectiveCamera} from "three/src/cameras/PerspectiveCamera.js";
|
||||
import {OrthographicCamera} from "three/src/cameras/OrthographicCamera.js";
|
||||
import {mdiClose, mdiCrosshairsGps, mdiDownload, mdiGithub, mdiLicense, mdiProjector} from '@mdi/js'
|
||||
import {
|
||||
mdiClose,
|
||||
mdiCrosshairsGps,
|
||||
mdiDownload,
|
||||
mdiGithub,
|
||||
mdiLicense,
|
||||
mdiLightbulb,
|
||||
mdiProjector,
|
||||
mdiScriptTextPlay
|
||||
} from '@mdi/js'
|
||||
// @ts-expect-error
|
||||
import SvgIcon from '@jamescoyle/vue-icon';
|
||||
import type {ModelViewerElement} from '@google/model-viewer';
|
||||
import Loading from "../misc/Loading.vue";
|
||||
import type ModelViewerWrapper from "../viewer/ModelViewerWrapper.vue";
|
||||
import {defineAsyncComponent, ref, type Ref} from "vue";
|
||||
import type {SelectionInfo} from "./selection";
|
||||
import {settings} from "../misc/settings.ts";
|
||||
import type {NetworkUpdateEvent} from "../misc/network.ts";
|
||||
import IfNotSmallBuild from "../misc/IfNotSmallBuild.vue";
|
||||
|
||||
const SelectionComponent = defineAsyncComponent({
|
||||
loader: () => import("./Selection.vue"),
|
||||
@@ -34,9 +47,22 @@ const LicensesDialogContent = defineAsyncComponent({
|
||||
delay: 0,
|
||||
});
|
||||
|
||||
const PlaygroundDialogContent = defineAsyncComponent({
|
||||
loader: () => import("./PlaygroundDialogContent.vue"),
|
||||
loadingComponent: Loading,
|
||||
delay: 0,
|
||||
});
|
||||
|
||||
|
||||
let props = defineProps<{ viewer: InstanceType<typeof ModelViewerWrapper> | null }>();
|
||||
const emit = defineEmits<{ findModel: [string] }>()
|
||||
const emit = defineEmits<{ findModel: [string], updateModel: [NetworkUpdateEvent] }>()
|
||||
|
||||
const sett = ref<any | null>(null);
|
||||
const showPlaygroundDialog = ref(false);
|
||||
(async () => {
|
||||
sett.value = await settings();
|
||||
showPlaygroundDialog.value = sett.value.pg_code != "";
|
||||
})();
|
||||
|
||||
let selection: Ref<Array<SelectionInfo>> = ref([]);
|
||||
let selectionFaceCount = () => selection.value.filter((s) => s.kind == 'face').length
|
||||
@@ -114,10 +140,14 @@ function removeObjectSelections(objName: string) {
|
||||
selectionComp.value?.updateDistances();
|
||||
}
|
||||
|
||||
defineExpose({removeObjectSelections});
|
||||
defineExpose({removeObjectSelections, openPlayground: () => showPlaygroundDialog.value = true});
|
||||
|
||||
// Add keyboard shortcuts
|
||||
window.addEventListener('keydown', (event) => {
|
||||
document.addEventListener('keydown', (event) => {
|
||||
if ((event.target as any)?.tagName && ((event.target as any).tagName === 'INPUT' || (event.target as any).tagName === 'TEXTAREA')) {
|
||||
// Ignore key events when an input is focused, except for text inputs
|
||||
return;
|
||||
}
|
||||
if (event.key === 'p') toggleProjection();
|
||||
else if (event.key === 'c') centerCamera();
|
||||
else if (event.key === 'd') downloadSceneGlb();
|
||||
@@ -139,6 +169,13 @@ window.addEventListener('keydown', (event) => {
|
||||
<v-tooltip activator="parent">Re(c)enter Camera</v-tooltip>
|
||||
<svg-icon :path="mdiCrosshairsGps" type="mdi"/>
|
||||
</v-btn>
|
||||
<span>
|
||||
<v-tooltip activator="parent">To rotate the light hold shift and drag the mouse or use two fingers<br/>
|
||||
Note that this breaks slightly clipping planes for now... (restart to fix)</v-tooltip>
|
||||
<v-btn icon disabled style="background: black;">
|
||||
<svg-icon :path="mdiLightbulb" type="mdi"/>
|
||||
</v-btn>
|
||||
</span>
|
||||
<v-divider/>
|
||||
<h5>Selection ({{ selectionFaceCount() }}F {{ selectionEdgeCount() }}E {{ selectionVertexCount() }}V)</h5>
|
||||
<selection-component ref="selectionComp" v-model="selection" :viewer="props.viewer as any"
|
||||
@@ -146,11 +183,26 @@ window.addEventListener('keydown', (event) => {
|
||||
<v-divider/>
|
||||
<v-spacer></v-spacer>
|
||||
<h5>Extras</h5>
|
||||
<v-dialog v-model="showPlaygroundDialog" persistent :scrim="false" attach="body">
|
||||
<template v-slot:activator="{ props }">
|
||||
<v-btn v-bind="props" style="width: 100%">
|
||||
<v-tooltip activator="parent">Open a python editor and build models directly in the browser!</v-tooltip>
|
||||
<svg-icon :path="mdiScriptTextPlay" type="mdi"/>
|
||||
Sandbox
|
||||
</v-btn>
|
||||
</template>
|
||||
<template v-slot:default="{ isActive }">
|
||||
<if-not-small-build>
|
||||
<playground-dialog-content v-if="sett != null" :initial-code="sett.pg_code" @close="isActive.value = false"
|
||||
@update-model="(event: NetworkUpdateEvent) => emit('updateModel', event)"/>
|
||||
</if-not-small-build>
|
||||
</template>
|
||||
</v-dialog>
|
||||
<v-btn icon @click="downloadSceneGlb">
|
||||
<v-tooltip activator="parent">(D)ownload Scene</v-tooltip>
|
||||
<svg-icon :path="mdiDownload" type="mdi"/>
|
||||
</v-btn>
|
||||
<v-dialog id="licenses-dialog" fullscreen>
|
||||
<v-dialog>
|
||||
<template v-slot:activator="{ props }">
|
||||
<v-btn icon v-bind="props">
|
||||
<v-tooltip activator="parent">Show Licenses</v-tooltip>
|
||||
@@ -158,11 +210,10 @@ window.addEventListener('keydown', (event) => {
|
||||
</v-btn>
|
||||
</template>
|
||||
<template v-slot:default="{ isActive }">
|
||||
<v-card>
|
||||
<v-toolbar>
|
||||
<v-card style="height: 90vh">
|
||||
<v-toolbar class="popup">
|
||||
<v-toolbar-title>Licenses</v-toolbar-title>
|
||||
<v-spacer>
|
||||
</v-spacer>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn icon @click="isActive.value = false">
|
||||
<svg-icon :path="mdiClose" type="mdi"/>
|
||||
</v-btn>
|
||||
@@ -199,4 +250,17 @@ window.addEventListener('keydown', (event) => {
|
||||
h5 {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.v-toolbar {
|
||||
position: sticky !important;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.v-toolbar.popup {
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
.v-toolbar.popup > div {
|
||||
height: 32px !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
54
frontend/tools/b66.ts
Normal file
54
frontend/tools/b66.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
// B66 encoding and decoding functions for compact url query parameter values. https://gist.github.com/danneu/6755394
|
||||
const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.-_~";
|
||||
|
||||
export function b66Encode(data: Uint8Array): string {
|
||||
let result = "";
|
||||
let bits = 0;
|
||||
let value = 0;
|
||||
|
||||
for (let byte of data) {
|
||||
value = (value << 8) | byte;
|
||||
bits += 8;
|
||||
|
||||
while (bits >= 6) {
|
||||
bits -= 6;
|
||||
result += alphabet[(value >> bits) & 0x3F];
|
||||
}
|
||||
}
|
||||
|
||||
if (bits > 0) {
|
||||
result += alphabet[(value << (6 - bits)) & 0x3F];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
export function b66Decode(encoded: string): Uint8Array {
|
||||
let result = [];
|
||||
let bits = 0;
|
||||
let value = 0;
|
||||
|
||||
for (let char of encoded) {
|
||||
const index = alphabet.indexOf(char);
|
||||
if (index === -1) {
|
||||
throw new Error(`Invalid character '${char}' in B66 encoded string.`);
|
||||
}
|
||||
|
||||
value = (value << 6) | index;
|
||||
bits += 6;
|
||||
|
||||
while (bits >= 8) {
|
||||
bits -= 8;
|
||||
result.push((value >> bits) & 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
if (bits > 0) {
|
||||
// If there are leftover bits, they should not be present in a valid B66 encoding.
|
||||
if (value << (8 - bits)) {
|
||||
throw new Error("Invalid B66 encoding: leftover bits.");
|
||||
}
|
||||
}
|
||||
|
||||
return new Uint8Array(result);
|
||||
}
|
||||
35
frontend/tools/monaco.ts
Normal file
35
frontend/tools/monaco.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import {loader} from "@guolao/vue-monaco-editor"
|
||||
|
||||
import * as monaco from "monaco-editor"
|
||||
//@ts-ignore
|
||||
import editorWorker from "monaco-editor/esm/vs/editor/editor.worker?worker"
|
||||
//@ts-ignore
|
||||
import jsonWorker from "monaco-editor/esm/vs/language/json/json.worker?worker"
|
||||
//@ts-ignore
|
||||
import cssWorker from "monaco-editor/esm/vs/language/css/css.worker?worker"
|
||||
//@ts-ignore
|
||||
import htmlWorker from "monaco-editor/esm/vs/language/html/html.worker?worker"
|
||||
//@ts-ignore
|
||||
import tsWorker from "monaco-editor/esm/vs/language/typescript/ts.worker?worker"
|
||||
|
||||
self.MonacoEnvironment = {
|
||||
getWorker(_, label) {
|
||||
if (label === "json") {
|
||||
return new jsonWorker()
|
||||
}
|
||||
if (label === "css" || label === "scss" || label === "less") {
|
||||
return new cssWorker()
|
||||
}
|
||||
if (label === "html" || label === "handlebars" || label === "razor") {
|
||||
return new htmlWorker()
|
||||
}
|
||||
if (label === "typescript" || label === "javascript") {
|
||||
return new tsWorker()
|
||||
}
|
||||
return new editorWorker()
|
||||
}
|
||||
}
|
||||
|
||||
export function setupMonaco() {
|
||||
loader.config({monaco})
|
||||
}
|
||||
31
frontend/tools/pyodide-worker-api.ts
Normal file
31
frontend/tools/pyodide-worker-api.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import type {loadPyodide} from "pyodide";
|
||||
|
||||
/** Simple API for the Pyodide worker. */
|
||||
export function newPyodideWorker(initOpts: Parameters<typeof loadPyodide>[0]) {
|
||||
let worker = new Worker(new URL('./pyodide-worker.ts', import.meta.url), {type: "module"});
|
||||
worker.postMessage(initOpts);
|
||||
return {
|
||||
asyncRun: (code: String, stdout: (msg: string) => void, stderr: (msg: string) => void) => new Promise((resolve, reject) => {
|
||||
worker.addEventListener("message", function listener(event) {
|
||||
if (event.data?.stdout) {
|
||||
stdout(event.data.stdout);
|
||||
return;
|
||||
}
|
||||
if (event.data?.stderr) {
|
||||
stderr(event.data.stderr);
|
||||
return;
|
||||
}
|
||||
// Result or error.
|
||||
worker.removeEventListener("message", listener);
|
||||
if (event.data?.error) {
|
||||
reject(event.data.error);
|
||||
} else {
|
||||
resolve(event.data?.result);
|
||||
}
|
||||
});
|
||||
worker.postMessage(code);
|
||||
}),
|
||||
terminate: () => worker.terminate()
|
||||
}
|
||||
}
|
||||
|
||||
33
frontend/tools/pyodide-worker.ts
Normal file
33
frontend/tools/pyodide-worker.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import {loadPyodide, type PyodideInterface} from "pyodide";
|
||||
|
||||
let myLoadPyodide = (initOpts: Parameters<typeof loadPyodide>[0]) => loadPyodide({
|
||||
...initOpts,
|
||||
stdout: (msg) => self.postMessage({stdout: msg + "\n"}), // Add newline for better readability
|
||||
stderr: (msg) => self.postMessage({stderr: msg + "\n"}), // Add newline for better readability
|
||||
stdin: () => {
|
||||
console.warn("Input requested by Python code, but stdin is not supported in this playground.");
|
||||
return "";
|
||||
},
|
||||
});
|
||||
|
||||
let pyodideReadyPromise: Promise<PyodideInterface> | null = null;
|
||||
|
||||
self.onmessage = async (event: MessageEvent<any>) => {
|
||||
if (!pyodideReadyPromise) { // First message is always the init message
|
||||
// If we haven't loaded Pyodide yet, do so now.
|
||||
// This is a singleton, so we only load it once.
|
||||
pyodideReadyPromise = myLoadPyodide(event.data as Parameters<typeof loadPyodide>[0]);
|
||||
return;
|
||||
}
|
||||
// All other messages are code to run.
|
||||
let code = event.data as string;
|
||||
// make sure loading is done
|
||||
const pyodide = await pyodideReadyPromise;
|
||||
// Now load any packages we need, run the code, and send the result back.
|
||||
await pyodide.loadPackagesFromImports(code);
|
||||
try {
|
||||
self.postMessage({result: await pyodide.runPythonAsync(code)});
|
||||
} catch (error: any) {
|
||||
self.postMessage({error: error.message});
|
||||
}
|
||||
};
|
||||
@@ -2,12 +2,13 @@ import {ModelViewerElement} from '@google/model-viewer';
|
||||
import {$scene} from "@google/model-viewer/lib/model-viewer-base";
|
||||
import {settings} from "../misc/settings.ts";
|
||||
|
||||
export let currentSceneRotation = 0; // radians, 0 is the default rotation
|
||||
|
||||
export async function setupLighting(modelViewer: ModelViewerElement) {
|
||||
modelViewer[$scene].environmentIntensity = (await settings()).environmentIntensity;
|
||||
// Code is mostly copied from the example at: https://modelviewer.dev/examples/stagingandcameras/#turnSkybox
|
||||
let lastX: number;
|
||||
let panning = false;
|
||||
let skyboxAngle = 0;
|
||||
let radiansPerPixel: number;
|
||||
|
||||
const startPan = () => {
|
||||
@@ -20,11 +21,11 @@ export async function setupLighting(modelViewer: ModelViewerElement) {
|
||||
const updatePan = (thisX: number) => {
|
||||
const delta = (thisX - lastX) * radiansPerPixel;
|
||||
lastX = thisX;
|
||||
skyboxAngle += delta;
|
||||
currentSceneRotation += delta;
|
||||
const orbit = modelViewer.getCameraOrbit();
|
||||
orbit.theta += delta;
|
||||
modelViewer.cameraOrbit = orbit.toString();
|
||||
modelViewer.resetTurntableRotation(skyboxAngle);
|
||||
modelViewer.resetTurntableRotation(currentSceneRotation);
|
||||
modelViewer.jumpCameraToGoal();
|
||||
}
|
||||
|
||||
|
||||
@@ -19,18 +19,24 @@
|
||||
"@gltf-transform/extensions": "^4.1.0",
|
||||
"@gltf-transform/functions": "^4.1.0",
|
||||
"@google/model-viewer": "^4.0.0",
|
||||
"@guolao/vue-monaco-editor": "^1.5.5",
|
||||
"@jamescoyle/vue-icon": "^0.1.2",
|
||||
"@mdi/js": "^7.4.47",
|
||||
"@mdi/svg": "^7.4.47",
|
||||
"js-base64": "^3.7.7",
|
||||
"monaco-editor": "^0.52.2",
|
||||
"pako": "^2.1.0",
|
||||
"pyodide": "^0.28.0",
|
||||
"three": "^0.178.0",
|
||||
"three-mesh-bvh": "^0.9.0",
|
||||
"three-orientation-gizmo": "https://github.com/jrj2211/three-orientation-gizmo",
|
||||
"three-orientation-gizmo": "git+https://github.com/jrj2211/three-orientation-gizmo.git",
|
||||
"vue": "^3.5.13",
|
||||
"vuetify": "^3.7.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tsconfig/node20": "^20.1.4",
|
||||
"@types/node": "^22.9.3",
|
||||
"@types/pako": "^2.0.3",
|
||||
"@types/three": "^0.178.0",
|
||||
"@vitejs/plugin-vue": "^6.0.0",
|
||||
"@vitejs/plugin-vue-jsx": "^5.0.0",
|
||||
@@ -42,6 +48,7 @@
|
||||
"terser": "^5.36.0",
|
||||
"typescript": "~5.8.0",
|
||||
"vite": "^7.0.0",
|
||||
"vite-plugin-static-copy": "^3.1.1",
|
||||
"vue-tsc": "^3.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
200
poetry.lock
generated
200
poetry.lock
generated
@@ -1,4 +1,4 @@
|
||||
# This file is automatically @generated by Poetry 1.8.5 and should not be changed by hand.
|
||||
# This file is automatically @generated by Poetry 2.1.2 and should not be changed by hand.
|
||||
|
||||
[[package]]
|
||||
name = "anytree"
|
||||
@@ -6,6 +6,7 @@ version = "2.13.0"
|
||||
description = "Powerful and Lightweight Python Tree Data Structure with various plugins"
|
||||
optional = false
|
||||
python-versions = "<4.0,>=3.9.2"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "anytree-2.13.0-py3-none-any.whl", hash = "sha256:4cbcf10df36b1f1cba131b7e487ff3edafc9d6e932a3c70071b5b768bab901ff"},
|
||||
{file = "anytree-2.13.0.tar.gz", hash = "sha256:c9d3aa6825fdd06af7ebb05b4ef291d2db63e62bb1f9b7d9b71354be9d362714"},
|
||||
@@ -17,6 +18,7 @@ version = "3.0.0"
|
||||
description = "Annotate AST trees with source code positions"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "asttokens-3.0.0-py3-none-any.whl", hash = "sha256:e3078351a059199dd5138cb1c706e6430c05eff2ff136af5eb4790f9d28932e2"},
|
||||
{file = "asttokens-3.0.0.tar.gz", hash = "sha256:0dcd8baa8d62b0c1d118b399b2ddba3c4aff271d0d7a9e0d4c1681c79035bbc7"},
|
||||
@@ -32,6 +34,7 @@ version = "0.9.1"
|
||||
description = "A python CAD programming library"
|
||||
optional = false
|
||||
python-versions = "<3.14,>=3.10"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "build123d-0.9.1-py3-none-any.whl", hash = "sha256:0e2a3c171d7db55329201438a95ab888df6c1b0fd13067a3780efcc8fbe1cc78"},
|
||||
{file = "build123d-0.9.1.tar.gz", hash = "sha256:8bc179cb65c7e7393191ad7113f13781fabf75892be07060f2bebf95369c093b"},
|
||||
@@ -63,6 +66,7 @@ version = "7.8.1.1.post1"
|
||||
description = "Python wrapper for Open CASCADE Technology 3D geometry library based on the official CadQuery/OCP sources"
|
||||
optional = false
|
||||
python-versions = "<3.14,>=3.10"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "cadquery_ocp-7.8.1.1.post1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4413961e98a90686a56c2ac58b126773c7da4eb82b967ddcc1f394fe6a7b71ad"},
|
||||
{file = "cadquery_ocp-7.8.1.1.post1-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:687c8a22d6248b28e44f136cecf93d274a897efbd0d8b36e38d4e207fecf1d84"},
|
||||
@@ -91,10 +95,12 @@ version = "0.4.6"
|
||||
description = "Cross-platform colored terminal text."
|
||||
optional = false
|
||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
|
||||
groups = ["main", "dev"]
|
||||
files = [
|
||||
{file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
|
||||
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
|
||||
]
|
||||
markers = {main = "sys_platform == \"win32\""}
|
||||
|
||||
[[package]]
|
||||
name = "contourpy"
|
||||
@@ -102,6 +108,7 @@ version = "1.3.2"
|
||||
description = "Python library for calculating contours of 2D quadrilateral grids"
|
||||
optional = false
|
||||
python-versions = ">=3.10"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "contourpy-1.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ba38e3f9f330af820c4b27ceb4b9c7feee5fe0493ea53a8720f4792667465934"},
|
||||
{file = "contourpy-1.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dc41ba0714aa2968d1f8674ec97504a8f7e334f48eeacebcaa6256213acb0989"},
|
||||
@@ -178,6 +185,7 @@ version = "0.12.1"
|
||||
description = "Composable style cycles"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30"},
|
||||
{file = "cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c"},
|
||||
@@ -193,6 +201,7 @@ version = "0.6.7"
|
||||
description = "Easily serialize dataclasses to and from JSON."
|
||||
optional = false
|
||||
python-versions = "<4.0,>=3.7"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "dataclasses_json-0.6.7-py3-none-any.whl", hash = "sha256:0dbf33f26c8d5305befd61b39d2b3414e8a407bedc2834dea9b8d642666fb40a"},
|
||||
{file = "dataclasses_json-0.6.7.tar.gz", hash = "sha256:b6b3e528266ea45b9535223bc53ca645f5208833c29229e847b3f26a1cc55fc0"},
|
||||
@@ -208,6 +217,7 @@ version = "5.2.1"
|
||||
description = "Decorators for Humans"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "decorator-5.2.1-py3-none-any.whl", hash = "sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a"},
|
||||
{file = "decorator-5.2.1.tar.gz", hash = "sha256:65f266143752f734b0a7cc83c46f4618af75b8c5911b00ccb61d0ac9b6da0360"},
|
||||
@@ -219,6 +229,7 @@ version = "1.2.18"
|
||||
description = "Python @deprecated decorator to deprecate old python classes, functions or methods."
|
||||
optional = false
|
||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "Deprecated-1.2.18-py2.py3-none-any.whl", hash = "sha256:bd5011788200372a32418f888e326a09ff80d0214bd961147cfed01b5c018eec"},
|
||||
{file = "deprecated-1.2.18.tar.gz", hash = "sha256:422b6f6d859da6f2ef57857761bfb392480502a64c3028ca9bbe86085d72115d"},
|
||||
@@ -228,7 +239,7 @@ files = [
|
||||
wrapt = ">=1.10,<2"
|
||||
|
||||
[package.extras]
|
||||
dev = ["PyTest", "PyTest-Cov", "bump2version (<1)", "setuptools", "tox"]
|
||||
dev = ["PyTest", "PyTest-Cov", "bump2version (<1)", "setuptools ; python_version >= \"3.12\"", "tox"]
|
||||
|
||||
[[package]]
|
||||
name = "exceptiongroup"
|
||||
@@ -236,6 +247,8 @@ version = "1.3.0"
|
||||
description = "Backport of PEP 654 (exception groups)"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
groups = ["main"]
|
||||
markers = "python_version == \"3.10\""
|
||||
files = [
|
||||
{file = "exceptiongroup-1.3.0-py3-none-any.whl", hash = "sha256:4d111e6e0c13d0644cad6ddaa7ed0261a0b36971f6d23e7ec9b4b9097da78a10"},
|
||||
{file = "exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88"},
|
||||
@@ -253,13 +266,14 @@ version = "2.2.0"
|
||||
description = "Get the currently executing AST node of a frame, and other information"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "executing-2.2.0-py2.py3-none-any.whl", hash = "sha256:11387150cad388d62750327a53d3339fad4888b39a6fe233c3afbb54ecffd3aa"},
|
||||
{file = "executing-2.2.0.tar.gz", hash = "sha256:5d108c028108fe2551d1a7b2e8b713341e2cb4fc0aa7dcf966fa4327a5226755"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipython", "littleutils", "pytest", "rich"]
|
||||
tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipython", "littleutils", "pytest", "rich ; python_version >= \"3.11\""]
|
||||
|
||||
[[package]]
|
||||
name = "ezdxf"
|
||||
@@ -267,6 +281,7 @@ version = "1.4.2"
|
||||
description = "A Python package to create/manipulate DXF drawings."
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "ezdxf-1.4.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:94e62d4da459d86e6d1630c09109b7b6fd9672f7ff8fab4eb9d3c91f75e0a18e"},
|
||||
{file = "ezdxf-1.4.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:63aae1eb68aa30e1bbee38886e5b8bf602c9a4a0b672f0b2b31c5cdb29d6c533"},
|
||||
@@ -330,6 +345,7 @@ version = "4.59.0"
|
||||
description = "Tools to manipulate font files"
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "fonttools-4.59.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:524133c1be38445c5c0575eacea42dbd44374b310b1ffc4b60ff01d881fabb96"},
|
||||
{file = "fonttools-4.59.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:21e606b2d38fed938dde871c5736822dd6bda7a4631b92e509a1f5cd1b90c5df"},
|
||||
@@ -376,17 +392,17 @@ files = [
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
all = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "lxml (>=4.0)", "lz4 (>=1.7.4.2)", "matplotlib", "munkres", "pycairo", "scipy", "skia-pathops (>=0.5.0)", "sympy", "uharfbuzz (>=0.23.0)", "unicodedata2 (>=15.1.0)", "xattr", "zopfli (>=0.1.4)"]
|
||||
all = ["brotli (>=1.0.1) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; platform_python_implementation != \"CPython\"", "lxml (>=4.0)", "lz4 (>=1.7.4.2)", "matplotlib", "munkres ; platform_python_implementation == \"PyPy\"", "pycairo", "scipy ; platform_python_implementation != \"PyPy\"", "skia-pathops (>=0.5.0)", "sympy", "uharfbuzz (>=0.23.0)", "unicodedata2 (>=15.1.0) ; python_version <= \"3.12\"", "xattr ; sys_platform == \"darwin\"", "zopfli (>=0.1.4)"]
|
||||
graphite = ["lz4 (>=1.7.4.2)"]
|
||||
interpolatable = ["munkres", "pycairo", "scipy"]
|
||||
interpolatable = ["munkres ; platform_python_implementation == \"PyPy\"", "pycairo", "scipy ; platform_python_implementation != \"PyPy\""]
|
||||
lxml = ["lxml (>=4.0)"]
|
||||
pathops = ["skia-pathops (>=0.5.0)"]
|
||||
plot = ["matplotlib"]
|
||||
repacker = ["uharfbuzz (>=0.23.0)"]
|
||||
symfont = ["sympy"]
|
||||
type1 = ["xattr"]
|
||||
unicode = ["unicodedata2 (>=15.1.0)"]
|
||||
woff = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "zopfli (>=0.1.4)"]
|
||||
type1 = ["xattr ; sys_platform == \"darwin\""]
|
||||
unicode = ["unicodedata2 (>=15.1.0) ; python_version <= \"3.12\""]
|
||||
woff = ["brotli (>=1.0.1) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; platform_python_implementation != \"CPython\"", "zopfli (>=0.1.4)"]
|
||||
|
||||
[[package]]
|
||||
name = "ipython"
|
||||
@@ -394,6 +410,7 @@ version = "8.37.0"
|
||||
description = "IPython: Productive Interactive Computing"
|
||||
optional = false
|
||||
python-versions = ">=3.10"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "ipython-8.37.0-py3-none-any.whl", hash = "sha256:ed87326596b878932dbcb171e3e698845434d8c61b8d8cd474bf663041a9dcf2"},
|
||||
{file = "ipython-8.37.0.tar.gz", hash = "sha256:ca815841e1a41a1e6b73a0b08f3038af9b2252564d01fc405356d34033012216"},
|
||||
@@ -415,7 +432,7 @@ typing_extensions = {version = ">=4.6", markers = "python_version < \"3.12\""}
|
||||
[package.extras]
|
||||
all = ["ipython[black,doc,kernel,matplotlib,nbconvert,nbformat,notebook,parallel,qtconsole]", "ipython[test,test-extra]"]
|
||||
black = ["black"]
|
||||
doc = ["docrepr", "exceptiongroup", "intersphinx_registry", "ipykernel", "ipython[test]", "matplotlib", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "sphinxcontrib-jquery", "tomli", "typing_extensions"]
|
||||
doc = ["docrepr", "exceptiongroup", "intersphinx_registry", "ipykernel", "ipython[test]", "matplotlib", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "sphinxcontrib-jquery", "tomli ; python_version < \"3.11\"", "typing_extensions"]
|
||||
kernel = ["ipykernel"]
|
||||
matplotlib = ["matplotlib"]
|
||||
nbconvert = ["nbconvert"]
|
||||
@@ -432,6 +449,7 @@ version = "0.19.2"
|
||||
description = "An autocompletion tool for Python that can be used for text editors."
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9"},
|
||||
{file = "jedi-0.19.2.tar.gz", hash = "sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0"},
|
||||
@@ -451,6 +469,7 @@ version = "1.4.8"
|
||||
description = "A fast implementation of the Cassowary constraint solver"
|
||||
optional = false
|
||||
python-versions = ">=3.10"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "kiwisolver-1.4.8-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:88c6f252f6816a73b1f8c904f7bbe02fd67c09a69f7cb8a0eecdbf5ce78e63db"},
|
||||
{file = "kiwisolver-1.4.8-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c72941acb7b67138f35b879bbe85be0f6c6a70cab78fe3ef6db9c024d9223e5b"},
|
||||
@@ -540,6 +559,7 @@ version = "3.26.1"
|
||||
description = "A lightweight library for converting complex datatypes to and from native Python datatypes."
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "marshmallow-3.26.1-py3-none-any.whl", hash = "sha256:3350409f20a70a7e4e11a27661187b77cdcaeb20abca41c1454fe33636bea09c"},
|
||||
{file = "marshmallow-3.26.1.tar.gz", hash = "sha256:e6d8affb6cb61d39d26402096dc0aee12d5a26d490a121f118d2e81dc0719dc6"},
|
||||
@@ -559,6 +579,7 @@ version = "3.10.3"
|
||||
description = "Python plotting package"
|
||||
optional = false
|
||||
python-versions = ">=3.10"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "matplotlib-3.10.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:213fadd6348d106ca7db99e113f1bea1e65e383c3ba76e8556ba4a3054b65ae7"},
|
||||
{file = "matplotlib-3.10.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d3bec61cb8221f0ca6313889308326e7bb303d0d302c5cc9e523b2f2e6c73deb"},
|
||||
@@ -616,6 +637,7 @@ version = "0.1.7"
|
||||
description = "Inline Matplotlib backend for Jupyter"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "matplotlib_inline-0.1.7-py3-none-any.whl", hash = "sha256:df192d39a4ff8f21b1895d72e6a13f5fcc5099f00fa84384e0ea28c2cc0653ca"},
|
||||
{file = "matplotlib_inline-0.1.7.tar.gz", hash = "sha256:8423b23ec666be3d16e16b60bdd8ac4e86e840ebd1dd11a30b9f117f2fa0ab90"},
|
||||
@@ -624,12 +646,26 @@ files = [
|
||||
[package.dependencies]
|
||||
traitlets = "*"
|
||||
|
||||
[[package]]
|
||||
name = "mslex"
|
||||
version = "1.3.0"
|
||||
description = "shlex for windows"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
groups = ["dev"]
|
||||
markers = "sys_platform == \"win32\""
|
||||
files = [
|
||||
{file = "mslex-1.3.0-py3-none-any.whl", hash = "sha256:c7074b347201b3466fc077c5692fbce9b5f62a63a51f537a53fbbd02eff2eea4"},
|
||||
{file = "mslex-1.3.0.tar.gz", hash = "sha256:641c887d1d3db610eee2af37a8e5abda3f70b3006cdfd2d0d29dc0d1ae28a85d"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mypy-extensions"
|
||||
version = "1.1.0"
|
||||
description = "Type system extensions for programs checked with the mypy type checker."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505"},
|
||||
{file = "mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558"},
|
||||
@@ -641,6 +677,7 @@ version = "2.2.6"
|
||||
description = "Fundamental package for array computing in Python"
|
||||
optional = false
|
||||
python-versions = ">=3.10"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "numpy-2.2.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b412caa66f72040e6d268491a59f2c43bf03eb6c96dd8f0307829feb7fa2b6fb"},
|
||||
{file = "numpy-2.2.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8e41fd67c52b86603a91c1a505ebaef50b3314de0213461c7a6e99c9a3beff90"},
|
||||
@@ -705,6 +742,7 @@ version = "0.5.0"
|
||||
description = ""
|
||||
optional = false
|
||||
python-versions = ">=3.10"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "ocpsvg-0.5.0-py3-none-any.whl", hash = "sha256:68cafdc3d681a1707530360baf2d51cfd58414b7d439f42eafbd31e842cf295e"},
|
||||
{file = "ocpsvg-0.5.0.tar.gz", hash = "sha256:5cd8dbec8bf590d373a82aaebeab241838185aab04ee2859f33b9d7956bbfba6"},
|
||||
@@ -723,6 +761,7 @@ version = "25.0"
|
||||
description = "Core utilities for Python packages"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484"},
|
||||
{file = "packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f"},
|
||||
@@ -734,6 +773,7 @@ version = "0.8.4"
|
||||
description = "A Python Parser"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "parso-0.8.4-py2.py3-none-any.whl", hash = "sha256:a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18"},
|
||||
{file = "parso-0.8.4.tar.gz", hash = "sha256:eb3a7b58240fb99099a345571deecc0f9540ea5f4dd2fe14c2a99d6b281ab92d"},
|
||||
@@ -749,6 +789,8 @@ version = "4.9.0"
|
||||
description = "Pexpect allows easy control of interactive console applications."
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
groups = ["main"]
|
||||
markers = "sys_platform != \"win32\" and sys_platform != \"emscripten\""
|
||||
files = [
|
||||
{file = "pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523"},
|
||||
{file = "pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f"},
|
||||
@@ -763,6 +805,7 @@ version = "11.3.0"
|
||||
description = "Python Imaging Library (Fork)"
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "pillow-11.3.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:1b9c17fd4ace828b3003dfd1e30bff24863e0eb59b535e8f80194d9cc7ecf860"},
|
||||
{file = "pillow-11.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:65dc69160114cdd0ca0f35cb434633c75e8e7fad4cf855177a05bf38678f73ad"},
|
||||
@@ -878,15 +921,28 @@ fpx = ["olefile"]
|
||||
mic = ["olefile"]
|
||||
test-arrow = ["pyarrow"]
|
||||
tests = ["check-manifest", "coverage (>=7.4.2)", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "trove-classifiers (>=2024.10.12)"]
|
||||
typing = ["typing-extensions"]
|
||||
typing = ["typing-extensions ; python_version < \"3.10\""]
|
||||
xmp = ["defusedxml"]
|
||||
|
||||
[[package]]
|
||||
name = "poetry-core"
|
||||
version = "2.1.3"
|
||||
description = "Poetry PEP 517 Build Backend"
|
||||
optional = false
|
||||
python-versions = "<4.0,>=3.9"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "poetry_core-2.1.3-py3-none-any.whl", hash = "sha256:2c704f05016698a54ca1d327f46ce2426d72eaca6ff614132c8477c292266771"},
|
||||
{file = "poetry_core-2.1.3.tar.gz", hash = "sha256:0522a015477ed622c89aad56a477a57813cace0c8e7ff2a2906b7ef4a2e296a4"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prompt-toolkit"
|
||||
version = "3.0.51"
|
||||
description = "Library for building powerful interactive command lines in Python"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "prompt_toolkit-3.0.51-py3-none-any.whl", hash = "sha256:52742911fde84e2d423e2f9a4cf1de7d7ac4e51958f648d9540e0fb8db077b07"},
|
||||
{file = "prompt_toolkit-3.0.51.tar.gz", hash = "sha256:931a162e3b27fc90c86f1b48bb1fb2c528c2761475e57c9c06de13311c7b54ed"},
|
||||
@@ -895,12 +951,45 @@ files = [
|
||||
[package.dependencies]
|
||||
wcwidth = "*"
|
||||
|
||||
[[package]]
|
||||
name = "psutil"
|
||||
version = "6.1.1"
|
||||
description = "Cross-platform lib for process and system monitoring in Python."
|
||||
optional = false
|
||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7"
|
||||
groups = ["dev"]
|
||||
files = [
|
||||
{file = "psutil-6.1.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:9ccc4316f24409159897799b83004cb1e24f9819b0dcf9c0b68bdcb6cefee6a8"},
|
||||
{file = "psutil-6.1.1-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:ca9609c77ea3b8481ab005da74ed894035936223422dc591d6772b147421f777"},
|
||||
{file = "psutil-6.1.1-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:8df0178ba8a9e5bc84fed9cfa61d54601b371fbec5c8eebad27575f1e105c0d4"},
|
||||
{file = "psutil-6.1.1-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:1924e659d6c19c647e763e78670a05dbb7feaf44a0e9c94bf9e14dfc6ba50468"},
|
||||
{file = "psutil-6.1.1-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:018aeae2af92d943fdf1da6b58665124897cfc94faa2ca92098838f83e1b1bca"},
|
||||
{file = "psutil-6.1.1-cp27-none-win32.whl", hash = "sha256:6d4281f5bbca041e2292be3380ec56a9413b790579b8e593b1784499d0005dac"},
|
||||
{file = "psutil-6.1.1-cp27-none-win_amd64.whl", hash = "sha256:c777eb75bb33c47377c9af68f30e9f11bc78e0f07fbf907be4a5d70b2fe5f030"},
|
||||
{file = "psutil-6.1.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:fc0ed7fe2231a444fc219b9c42d0376e0a9a1a72f16c5cfa0f68d19f1a0663e8"},
|
||||
{file = "psutil-6.1.1-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:0bdd4eab935276290ad3cb718e9809412895ca6b5b334f5a9111ee6d9aff9377"},
|
||||
{file = "psutil-6.1.1-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b6e06c20c05fe95a3d7302d74e7097756d4ba1247975ad6905441ae1b5b66003"},
|
||||
{file = "psutil-6.1.1-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97f7cb9921fbec4904f522d972f0c0e1f4fabbdd4e0287813b21215074a0f160"},
|
||||
{file = "psutil-6.1.1-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:33431e84fee02bc84ea36d9e2c4a6d395d479c9dd9bba2376c1f6ee8f3a4e0b3"},
|
||||
{file = "psutil-6.1.1-cp36-cp36m-win32.whl", hash = "sha256:384636b1a64b47814437d1173be1427a7c83681b17a450bfc309a1953e329603"},
|
||||
{file = "psutil-6.1.1-cp36-cp36m-win_amd64.whl", hash = "sha256:8be07491f6ebe1a693f17d4f11e69d0dc1811fa082736500f649f79df7735303"},
|
||||
{file = "psutil-6.1.1-cp37-abi3-win32.whl", hash = "sha256:eaa912e0b11848c4d9279a93d7e2783df352b082f40111e078388701fd479e53"},
|
||||
{file = "psutil-6.1.1-cp37-abi3-win_amd64.whl", hash = "sha256:f35cfccb065fff93529d2afb4a2e89e363fe63ca1e4a5da22b603a85833c2649"},
|
||||
{file = "psutil-6.1.1.tar.gz", hash = "sha256:cf8496728c18f2d0b45198f06895be52f36611711746b7f30c464b422b50e2f5"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
dev = ["abi3audit", "black", "check-manifest", "coverage", "packaging", "pylint", "pyperf", "pypinfo", "pytest-cov", "requests", "rstcheck", "ruff", "sphinx", "sphinx_rtd_theme", "toml-sort", "twine", "virtualenv", "vulture", "wheel"]
|
||||
test = ["pytest", "pytest-xdist", "setuptools"]
|
||||
|
||||
[[package]]
|
||||
name = "ptyprocess"
|
||||
version = "0.7.0"
|
||||
description = "Run a subprocess in a pseudo terminal"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
groups = ["main"]
|
||||
markers = "sys_platform != \"win32\" and sys_platform != \"emscripten\""
|
||||
files = [
|
||||
{file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"},
|
||||
{file = "ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"},
|
||||
@@ -912,6 +1001,7 @@ version = "0.2.3"
|
||||
description = "Safely evaluate AST nodes without side effects"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0"},
|
||||
{file = "pure_eval-0.2.3.tar.gz", hash = "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42"},
|
||||
@@ -926,19 +1016,21 @@ version = "2.3.1"
|
||||
description = "A python package for Lib3MF tools"
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "py_lib3mf-2.3.1-py3-none-any.whl", hash = "sha256:86a870ef386debba9b74683d3a08125a34c153aaa65e967f61677cc5a0a65e24"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pygltflib"
|
||||
version = "1.16.4"
|
||||
version = "1.16.5"
|
||||
description = "Python library for reading, writing and managing 3D objects in the Khronos Group gltf and gltf2 formats."
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "pygltflib-1.16.4-py3-none-any.whl", hash = "sha256:1cb5886ca12ac512bbea3b5640f1e15575844418b1f1574de42ec19175e00f53"},
|
||||
{file = "pygltflib-1.16.4.tar.gz", hash = "sha256:7816253ef51b07a208864b94332bce8c509aa0f9b827d8771cf271293ecebb11"},
|
||||
{file = "pygltflib-1.16.5-py3-none-any.whl", hash = "sha256:41d3349c59dcf1586faeaee29c967be07ac2bf7cecdb8ae2b527da1f25afdaac"},
|
||||
{file = "pygltflib-1.16.5.tar.gz", hash = "sha256:1f15740d5a7aaf71a5083e285af6b361184958e255659132f4ba8fe4f3d21ea9"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@@ -951,6 +1043,7 @@ version = "2.19.2"
|
||||
description = "Pygments is a syntax highlighting package written in Python."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b"},
|
||||
{file = "pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887"},
|
||||
@@ -965,6 +1058,7 @@ version = "3.2.3"
|
||||
description = "pyparsing module - Classes and methods to define and execute parsing grammars"
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "pyparsing-3.2.3-py3-none-any.whl", hash = "sha256:a749938e02d6fd0b59b356ca504a24982314bb090c383e3cf201c95ef7e2bfcf"},
|
||||
{file = "pyparsing-3.2.3.tar.gz", hash = "sha256:b9c13f1ab8b3b542f72e28f634bad4de758ab3ce4546e4301970ad6fa77c38be"},
|
||||
@@ -979,6 +1073,7 @@ version = "2.9.0.post0"
|
||||
description = "Extensions to the standard Python datetime module"
|
||||
optional = false
|
||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"},
|
||||
{file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"},
|
||||
@@ -993,6 +1088,7 @@ version = "1.15.3"
|
||||
description = "Fundamental algorithms for scientific computing in Python"
|
||||
optional = false
|
||||
python-versions = ">=3.10"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "scipy-1.15.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:a345928c86d535060c9c2b25e71e87c39ab2f22fc96e9636bd74d1dbf9de448c"},
|
||||
{file = "scipy-1.15.3-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:ad3432cb0f9ed87477a8d97f03b763fd1d57709f1bbde3c9369b1dff5503b253"},
|
||||
@@ -1048,7 +1144,7 @@ numpy = ">=1.23.5,<2.5"
|
||||
[package.extras]
|
||||
dev = ["cython-lint (>=0.12.2)", "doit (>=0.36.0)", "mypy (==1.10.0)", "pycodestyle", "pydevtool", "rich-click", "ruff (>=0.0.292)", "types-psutil", "typing_extensions"]
|
||||
doc = ["intersphinx_registry", "jupyterlite-pyodide-kernel", "jupyterlite-sphinx (>=0.19.1)", "jupytext", "matplotlib (>=3.5)", "myst-nb", "numpydoc", "pooch", "pydata-sphinx-theme (>=0.15.2)", "sphinx (>=5.0.0,<8.0.0)", "sphinx-copybutton", "sphinx-design (>=0.4.0)"]
|
||||
test = ["Cython", "array-api-strict (>=2.0,<2.1.1)", "asv", "gmpy2", "hypothesis (>=6.30)", "meson", "mpmath", "ninja", "pooch", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "scikit-umfpack", "threadpoolctl"]
|
||||
test = ["Cython", "array-api-strict (>=2.0,<2.1.1)", "asv", "gmpy2", "hypothesis (>=6.30)", "meson", "mpmath", "ninja ; sys_platform != \"emscripten\"", "pooch", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "scikit-umfpack", "threadpoolctl"]
|
||||
|
||||
[[package]]
|
||||
name = "six"
|
||||
@@ -1056,6 +1152,7 @@ version = "1.17.0"
|
||||
description = "Python 2 and 3 compatibility utilities"
|
||||
optional = false
|
||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"},
|
||||
{file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"},
|
||||
@@ -1067,6 +1164,7 @@ version = "0.6.3"
|
||||
description = "Extract data from python stack frames and tracebacks for informative displays"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695"},
|
||||
{file = "stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9"},
|
||||
@@ -1086,6 +1184,7 @@ version = "1.9.6"
|
||||
description = "Svg Elements Parsing"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "svgelements-1.9.6-py2.py3-none-any.whl", hash = "sha256:8a5cf2cc066d98e713d5b875b1d6e5eeb9b92e855e835ebd7caab2713ae1dcad"},
|
||||
{file = "svgelements-1.9.6.tar.gz", hash = "sha256:7c02ad6404cd3d1771fd50e40fbfc0550b0893933466f86a6eb815f3ba3f37f7"},
|
||||
@@ -1097,6 +1196,7 @@ version = "1.7.1"
|
||||
description = "A collection of tools for manipulating and analyzing SVG Path objects and Bezier curves."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "svgpathtools-1.7.1-py2.py3-none-any.whl", hash = "sha256:3cbb8ba0e8d200f9639034608d9c55b68efbc1bef99ea99559a3e7cb024fb738"},
|
||||
{file = "svgpathtools-1.7.1.tar.gz", hash = "sha256:beaef20fd78164aa5f0a7d4fd164ef20cb0d3d015cdec50c8c168e9d6547f041"},
|
||||
@@ -1113,17 +1213,79 @@ version = "1.4.3"
|
||||
description = "A Python library to create SVG drawings."
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "svgwrite-1.4.3-py3-none-any.whl", hash = "sha256:bb6b2b5450f1edbfa597d924f9ac2dd099e625562e492021d7dd614f65f8a22d"},
|
||||
{file = "svgwrite-1.4.3.zip", hash = "sha256:a8fbdfd4443302a6619a7f76bc937fc683daf2628d9b737c891ec08b8ce524c3"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "taskipy"
|
||||
version = "1.14.1"
|
||||
description = "tasks runner for python projects"
|
||||
optional = false
|
||||
python-versions = "<4.0,>=3.6"
|
||||
groups = ["dev"]
|
||||
files = [
|
||||
{file = "taskipy-1.14.1-py3-none-any.whl", hash = "sha256:6e361520f29a0fd2159848e953599f9c75b1d0b047461e4965069caeb94908f1"},
|
||||
{file = "taskipy-1.14.1.tar.gz", hash = "sha256:410fbcf89692dfd4b9f39c2b49e1750b0a7b81affd0e2d7ea8c35f9d6a4774ed"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
colorama = ">=0.4.4,<0.5.0"
|
||||
mslex = {version = ">=1.1.0,<2.0.0", markers = "sys_platform == \"win32\""}
|
||||
psutil = ">=5.7.2,<7"
|
||||
tomli = {version = ">=2.0.1,<3.0.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""}
|
||||
|
||||
[[package]]
|
||||
name = "tomli"
|
||||
version = "2.2.1"
|
||||
description = "A lil' TOML parser"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
groups = ["dev"]
|
||||
files = [
|
||||
{file = "tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249"},
|
||||
{file = "tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6"},
|
||||
{file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a"},
|
||||
{file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee"},
|
||||
{file = "tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e"},
|
||||
{file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4"},
|
||||
{file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106"},
|
||||
{file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8"},
|
||||
{file = "tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff"},
|
||||
{file = "tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b"},
|
||||
{file = "tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea"},
|
||||
{file = "tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8"},
|
||||
{file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192"},
|
||||
{file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222"},
|
||||
{file = "tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77"},
|
||||
{file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6"},
|
||||
{file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd"},
|
||||
{file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e"},
|
||||
{file = "tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98"},
|
||||
{file = "tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4"},
|
||||
{file = "tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7"},
|
||||
{file = "tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c"},
|
||||
{file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13"},
|
||||
{file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281"},
|
||||
{file = "tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272"},
|
||||
{file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140"},
|
||||
{file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2"},
|
||||
{file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744"},
|
||||
{file = "tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec"},
|
||||
{file = "tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69"},
|
||||
{file = "tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc"},
|
||||
{file = "tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "traitlets"
|
||||
version = "5.14.3"
|
||||
description = "Traitlets Python configuration system"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f"},
|
||||
{file = "traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7"},
|
||||
@@ -1139,6 +1301,7 @@ version = "1.2"
|
||||
description = "Find all the sides and angles of a triangle, if you know some of the sides and/or angles. (Uses the Law of Sines and Law of Cosines.)"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "trianglesolver-1.2-py3-none-any.whl", hash = "sha256:aa0903c3708b4e2b496f06d490cae72c6ff6274b00d1edce420fcfa3b2b76682"},
|
||||
{file = "trianglesolver-1.2.tar.gz", hash = "sha256:4af18aade579d5c0d64389b3e65aeaf06cff26319762ccd859e3268559a76aea"},
|
||||
@@ -1150,6 +1313,7 @@ version = "4.14.1"
|
||||
description = "Backported and Experimental Type Hints for Python 3.9+"
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "typing_extensions-4.14.1-py3-none-any.whl", hash = "sha256:d1e1e3b58374dc93031d6eda2420a48ea44a36c2b4766a4fdeb3710755731d76"},
|
||||
{file = "typing_extensions-4.14.1.tar.gz", hash = "sha256:38b39f4aeeab64884ce9f74c94263ef78f3c22467c8724005483154c26648d36"},
|
||||
@@ -1161,6 +1325,7 @@ version = "0.9.0"
|
||||
description = "Runtime inspection utilities for typing module."
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "typing_inspect-0.9.0-py3-none-any.whl", hash = "sha256:9ee6fc59062311ef8547596ab6b955e1b8aa46242d854bfc78f4f6b0eff35f9f"},
|
||||
{file = "typing_inspect-0.9.0.tar.gz", hash = "sha256:b23fc42ff6f6ef6954e4852c1fb512cdd18dbea03134f91f856a95ccc9461f78"},
|
||||
@@ -1176,6 +1341,7 @@ version = "9.3.1"
|
||||
description = "VTK is an open-source toolkit for 3D computer graphics, image processing, and visualization"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "vtk-9.3.1-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:c41ed344b9cc90ee9dcfc5967815de272985647d0c8e0a57f0e8b4229bc1b0b9"},
|
||||
{file = "vtk-9.3.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:84c04327becc4c4dfe1fb04248baa4b5c480f188a9d52f4b912b163d33622442"},
|
||||
@@ -1217,6 +1383,7 @@ version = "0.2.13"
|
||||
description = "Measures the displayed width of unicode strings in a terminal"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859"},
|
||||
{file = "wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5"},
|
||||
@@ -1228,6 +1395,7 @@ version = "1.17.2"
|
||||
description = "Module for decorators, wrappers and monkey patching."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "wrapt-1.17.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3d57c572081fed831ad2d26fd430d565b76aa277ed1d30ff4d40670b1c0dd984"},
|
||||
{file = "wrapt-1.17.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b5e251054542ae57ac7f3fba5d10bfff615b6c2fb09abeb37d2f1463f841ae22"},
|
||||
@@ -1311,6 +1479,6 @@ files = [
|
||||
]
|
||||
|
||||
[metadata]
|
||||
lock-version = "2.0"
|
||||
lock-version = "2.1"
|
||||
python-versions = ">=3.10,<3.13"
|
||||
content-hash = "93d841ad150ea31f388ae73a764e7a0491e65ace01fa1bad7b66dbf6cba4b459"
|
||||
content-hash = "17564ce50af9a75e84337c83f77d86c9d2ff73a366de70ba27453e529bb468e9"
|
||||
|
||||
@@ -1,15 +1,24 @@
|
||||
[build-system]
|
||||
requires = ["poetry-core==2.1.3", "taskipy==1.14.1"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
|
||||
[tool.poetry]
|
||||
name = "yacv-server"
|
||||
version = "0.9.7"
|
||||
version = "0.10.0-alpha.4"
|
||||
description = "Yet Another CAD Viewer (server)"
|
||||
authors = ["Yeicor <4929005+Yeicor@users.noreply.github.com>"]
|
||||
license = "MIT"
|
||||
readme = "README.md"
|
||||
include = [
|
||||
{ path = 'yacv_server/frontend/*', format = 'wheel' },
|
||||
{ path = 'yacv_server/frontend/*', format = 'sdist' },
|
||||
{ path = 'yacv_server/frontend/**/*', format = 'wheel' },
|
||||
{ path = 'yacv_server/frontend/**/*', format = 'sdist' },
|
||||
]
|
||||
|
||||
[tool.taskipy.tasks]
|
||||
build = "task build_frontend && task build_backend"
|
||||
build_frontend = "rm -rf yacv_server/frontend || true && yarn install && YACV_SMALL_BUILD=true yarn build --outDir yacv_server/frontend"
|
||||
build_backend = "poetry build --format wheel"
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = ">=3.10,<3.13" # Due to vtk transitive dependency of build123d -> cadquery-ocp -> vtk
|
||||
|
||||
@@ -19,11 +28,7 @@ build123d = ">=0.9,<0.10"
|
||||
# Misc
|
||||
pygltflib = "^1.16.2"
|
||||
pillow = ">=10.2,<12.0"
|
||||
poetry-core = "==2.1.3"
|
||||
|
||||
[tool.poetry.build]
|
||||
generate-setup-file = false
|
||||
script = "build.py"
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
[tool.poetry.group.dev.dependencies]
|
||||
taskipy = "^1.14.1"
|
||||
|
||||
@@ -1,10 +1,17 @@
|
||||
import {fileURLToPath, URL} from 'node:url'
|
||||
|
||||
import {defineConfig} from 'vite'
|
||||
// @ts-ignore
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
// @ts-ignore
|
||||
import vueJsx from '@vitejs/plugin-vue-jsx'
|
||||
import {name, version} from './package.json'
|
||||
import {execSync} from 'child_process'
|
||||
import {viteStaticCopy} from "vite-plugin-static-copy";
|
||||
import {dirname, join} from "path";
|
||||
import {version as pyodideVersion} from "pyodide";
|
||||
|
||||
let wantsSmallBuild = process.env.YACV_SMALL_BUILD == "true";
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
@@ -13,12 +20,14 @@ export default defineConfig({
|
||||
vue({
|
||||
template: {
|
||||
compilerOptions: {
|
||||
isCustomElement: tag => tag == 'model-viewer'
|
||||
isCustomElement: (tag: string) => tag == 'model-viewer'
|
||||
}
|
||||
}
|
||||
}),
|
||||
vueJsx(),
|
||||
viteStaticCopyPyodide(),
|
||||
],
|
||||
optimizeDeps: {exclude: ["pyodide"]},
|
||||
resolve: {
|
||||
alias: {
|
||||
// @ts-ignore
|
||||
@@ -28,13 +37,51 @@ export default defineConfig({
|
||||
build: {
|
||||
assetsDir: '.', // Support deploying to a subdirectory using relative URLs
|
||||
cssCodeSplit: false, // Small enough to inline
|
||||
chunkSizeWarningLimit: 1024, // Three.js is big. Draco is even bigger but not likely to be used.
|
||||
chunkSizeWarningLimit: 1024, // KB. Three.js is big. Draco is even bigger but not likely to be used.
|
||||
sourcemap: true, // For debugging production
|
||||
rollupOptions: {
|
||||
output: {
|
||||
experimentalMinChunkSize: 512000, // 512KB (avoid too many small chunks)
|
||||
},
|
||||
external: wantsSmallBuild ? [
|
||||
// Exclude some large optional dependencies if small build is requested (for embedding in python package)
|
||||
"pyodide",
|
||||
/.*\/pyodide-worker.*/,
|
||||
"monaco-editor",
|
||||
/monaco-editor\/.*/,
|
||||
"@guolao/vue-monaco-editor",
|
||||
/three\/examples\/jsm\/libs\/draco\/draco_(en|de)coder\.js/,
|
||||
] : [],
|
||||
},
|
||||
},
|
||||
worker: {
|
||||
format: 'es', // Use ES modules for workers (IIFE is not supported with code-splitting)
|
||||
},
|
||||
define: {
|
||||
__APP_NAME__: JSON.stringify(name),
|
||||
__APP_VERSION__: JSON.stringify(version),
|
||||
__APP_GIT_SHA__: JSON.stringify(execSync('git rev-parse HEAD').toString().trim()),
|
||||
__APP_GIT_DIRTY__: JSON.stringify(execSync('git diff --quiet || echo dirty').toString().trim()),
|
||||
__YACV_SMALL_BUILD__: JSON.stringify(wantsSmallBuild),
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
function viteStaticCopyPyodide() {
|
||||
const PYODIDE_EXCLUDE = [
|
||||
"!**/*.{md,html}",
|
||||
"!**/*.d.ts",
|
||||
"!**/*.whl",
|
||||
"!**/node_modules",
|
||||
];
|
||||
// @ts-ignore
|
||||
const pyodideDir = dirname(fileURLToPath(import.meta.resolve("pyodide")));
|
||||
return viteStaticCopy({
|
||||
targets: wantsSmallBuild ? [] : [
|
||||
{
|
||||
src: [join(pyodideDir, "*")].concat(PYODIDE_EXCLUDE),
|
||||
dest: "pyodide-v" + pyodideVersion, // It would be better to use hashed names instead of folder...
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
@@ -54,8 +54,8 @@ class BufferedPubSub(Generic[T]):
|
||||
self._subscribers.remove(q)
|
||||
logger.debug(f"Unsubscribed from %s (%d subscribers)", self, len(self._subscribers))
|
||||
|
||||
def subscribe(self, include_buffered: bool = True, include_future: bool = True, yield_timeout: float = 0.0) -> \
|
||||
Generator[T, None, None]:
|
||||
def subscribe(self, include_buffered: bool = True, include_future: bool = True,
|
||||
yield_timeout: float | None = 0.0) -> Generator[T, None, None]:
|
||||
"""Subscribes to events as a generator that yields events and automatically unsubscribes"""
|
||||
q = self._subscribe(include_buffered, include_future)
|
||||
try:
|
||||
|
||||
@@ -3,8 +3,8 @@ from typing import List, Dict, Tuple, Optional
|
||||
from OCP.BRep import BRep_Tool
|
||||
from OCP.BRepAdaptor import BRepAdaptor_Curve
|
||||
from OCP.GCPnts import GCPnts_TangentialDeflection
|
||||
from OCP.OCP.BRepLib import BRepLib_ToolTriangulatedShape
|
||||
from OCP.OCP.TopAbs import TopAbs_Orientation
|
||||
from OCP.BRepLib import BRepLib_ToolTriangulatedShape
|
||||
from OCP.TopAbs import TopAbs_Orientation
|
||||
from OCP.TopLoc import TopLoc_Location
|
||||
from OCP.TopoDS import TopoDS_Face, TopoDS_Edge, TopoDS_Shape, TopoDS_Vertex
|
||||
from build123d import Vertex, Face, Location, Compound, Vector
|
||||
|
||||
@@ -8,6 +8,7 @@ import sys
|
||||
import threading
|
||||
import time
|
||||
from dataclasses import dataclass
|
||||
from enum import Enum, auto
|
||||
from http.server import ThreadingHTTPServer
|
||||
from io import BytesIO
|
||||
from threading import Thread
|
||||
@@ -64,10 +65,20 @@ class UpdatesApiFullData(UpdatesApiData):
|
||||
return super().to_json()
|
||||
|
||||
|
||||
class YACVProtocol(Enum):
|
||||
"""Enum of communication protocols supported by the server"""
|
||||
HTTP = auto()
|
||||
"""The recommended protocol for any platform that can run a web server."""
|
||||
STDERR = auto()
|
||||
"""Prints the updates one by one to stderr (first metadata, then base64 of glb file) using a special prefix. Required for Pyodide support."""
|
||||
|
||||
|
||||
class YACV:
|
||||
"""The main yacv_server class, which manages the web server and the CAD objects."""
|
||||
|
||||
# Startup
|
||||
protocol: YACVProtocol
|
||||
"""The protocol used by the server. Defaults to HTTP, but can be set to STDERR for Pyodide support."""
|
||||
server_thread: Optional[Thread]
|
||||
"""The main thread running the server (will spawn other threads for each request)"""
|
||||
server: Optional[ThreadingHTTPServer]
|
||||
@@ -127,6 +138,10 @@ class YACV:
|
||||
in the hexadecimal format #RRGGBB or #RRGGBBAA."""
|
||||
|
||||
def __init__(self):
|
||||
"""Initializes the YACV server"""
|
||||
raw_protocol = os.getenv('YACV_PROTOCOL', 'http' if sys.platform != 'emscripten' else 'stderr').upper()
|
||||
self.protocol = YACVProtocol[raw_protocol] if raw_protocol in YACVProtocol.__members__ else YACVProtocol.HTTP
|
||||
self.protocol = YACVProtocol.STDERR
|
||||
self.server_thread = None
|
||||
self.server = None
|
||||
self.startup_complete = threading.Event()
|
||||
@@ -144,6 +159,7 @@ class YACV:
|
||||
|
||||
def start(self):
|
||||
"""Starts the web server in the background"""
|
||||
if self.protocol == YACVProtocol.STDERR: return # No server to start, just print to stderr
|
||||
assert self.server_thread is None, "Server currently running, cannot start another one"
|
||||
assert self.startup_complete.is_set() is False, "Server already started"
|
||||
# Start the server in a separate daemon thread
|
||||
@@ -160,6 +176,8 @@ class YACV:
|
||||
# noinspection PyUnusedLocal
|
||||
def stop(self, *args):
|
||||
"""Stops the web server"""
|
||||
if self.protocol == YACVProtocol.STDERR: return # No server to stop, just print to stderr
|
||||
# The remainder is for the HTTP protocol only
|
||||
if self.server_thread is None:
|
||||
logger.error('Cannot stop server because it is not running')
|
||||
return
|
||||
@@ -167,7 +185,7 @@ class YACV:
|
||||
# Inform the server that we are shutting down
|
||||
self.shutting_down.set()
|
||||
# noinspection PyTypeChecker
|
||||
self.show_events.publish(UpdatesApiFullData(name='__shutdown', _hash='', is_remove=None, obj=None))
|
||||
self._show_event(UpdatesApiFullData(name='__shutdown', _hash='', is_remove=None, obj=None))
|
||||
|
||||
# If we were too fast, ensure that at least one client has connected
|
||||
graceful_secs_connect = float(os.getenv('YACV_GRACEFUL_SECS_CONNECT', 12.0))
|
||||
@@ -195,9 +213,11 @@ class YACV:
|
||||
if len(args) >= 1 and args[0] in (signal.SIGINT, signal.SIGTERM):
|
||||
sys.exit(0) # Exit with success
|
||||
|
||||
_yacvServerModelPrefix = "yacv_server://model/"
|
||||
|
||||
def _run_server(self):
|
||||
"""Runs the web server"""
|
||||
logger.info('Starting server...')
|
||||
logger.info('Starting server in %s mode...', self.protocol.name)
|
||||
self.server = ThreadingHTTPServer(
|
||||
(os.getenv('YACV_HOST', 'localhost'), int(os.getenv('YACV_PORT', 32323))),
|
||||
lambda a, b, c: HTTPHandler(a, b, c, yacv=self))
|
||||
@@ -206,6 +226,22 @@ class YACV:
|
||||
self.startup_complete.set()
|
||||
self.server.serve_forever()
|
||||
|
||||
def _show_event(self, event: UpdatesApiFullData):
|
||||
"""Handles a show event by publishing it to the show events buffer (and special handling for stderr protocol)."""
|
||||
self.show_events.publish(event)
|
||||
# If the protocol is STDERR, we need to print the event to stderr
|
||||
if self.protocol == YACVProtocol.STDERR:
|
||||
msg = f'{self._yacvServerModelPrefix}{event.to_json()}'
|
||||
if not event.is_remove:
|
||||
# Always build the object even if the interface already has it (optimization disabled for Pyodide)
|
||||
glb_and_hash = self.export(event.name)
|
||||
if glb_and_hash is None:
|
||||
logger.warning('Object %s not found, ignoring it...', event.name)
|
||||
return
|
||||
glb = glb_and_hash[0]
|
||||
msg += f'{base64.b64encode(glb).decode("utf-8")}'
|
||||
print(msg, file=sys.stderr, flush=True)
|
||||
|
||||
def show(self, *objs: List[YACVSupported], names: Optional[Union[str, List[str]]] = None, **kwargs):
|
||||
"""
|
||||
Shows the given CAD objects in the frontend. The objects will be tessellated and converted to GLTF. Optionally,
|
||||
@@ -252,13 +288,13 @@ class YACV:
|
||||
# Some properties may be lost in preprocessing, so save them in kwargs
|
||||
_kwargs = kwargs.copy()
|
||||
if obj_color is not None:
|
||||
_kwargs['color_obj'] = obj_color # Only applies to highest-dimensional objects
|
||||
_kwargs['color_obj'] = obj_color # Only applies to highest-dimensional objects
|
||||
_kwargs['texture'] = _read_texture_uri(getattr(obj, 'yacv_texture', None) or kwargs.get('texture', None))
|
||||
if not isinstance(obj, bytes):
|
||||
obj = _preprocess_cad(obj, **_kwargs)
|
||||
_hash = _hashcode(obj, **_kwargs)
|
||||
event = UpdatesApiFullData(name=name, _hash=_hash, obj=obj, kwargs=_kwargs or {})
|
||||
self.show_events.publish(event)
|
||||
self._show_event(event)
|
||||
|
||||
logger.info('show %s took %.3f seconds', names, time.time() - start)
|
||||
|
||||
@@ -283,7 +319,7 @@ class YACV:
|
||||
# Publish the remove event
|
||||
show_event = copy.copy(show_events[-1])
|
||||
show_event.is_remove = True
|
||||
self.show_events.publish(show_event)
|
||||
self._show_event(show_event)
|
||||
|
||||
def clear(self, except_names: List[str] = None):
|
||||
"""Clears all previously-shown objects from the scene"""
|
||||
|
||||
409
yarn.lock
409
yarn.lock
@@ -162,14 +162,14 @@
|
||||
integrity sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==
|
||||
|
||||
"@babel/helpers@^7.27.6":
|
||||
version "7.27.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.27.6.tgz#6456fed15b2cb669d2d1fabe84b66b34991d812c"
|
||||
integrity sha512-muE8Tt8M22638HU31A3CgfSUciwz1fhATfoVai05aPXGor//CdWDCbnlY1yvBPo07njuVOCNGCSp/GTt12lIug==
|
||||
version "7.28.2"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.28.2.tgz#80f0918fecbfebea9af856c419763230040ee850"
|
||||
integrity sha512-/V9771t+EgXz62aCcyofnQhGM8DQACbRhvzKFsXKC9QM+5MadF8ZmIm0crDMaz3+o0h0zXfJnd4EhbYbxsrcFw==
|
||||
dependencies:
|
||||
"@babel/template" "^7.27.2"
|
||||
"@babel/types" "^7.27.6"
|
||||
"@babel/types" "^7.28.2"
|
||||
|
||||
"@babel/parser@^7.26.9", "@babel/parser@^7.27.2", "@babel/parser@^7.27.5", "@babel/parser@^7.28.0":
|
||||
"@babel/parser@^7.26.9", "@babel/parser@^7.27.2", "@babel/parser@^7.28.0":
|
||||
version "7.28.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.28.0.tgz#979829fbab51a29e13901e5a80713dbcb840825e"
|
||||
integrity sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==
|
||||
@@ -223,10 +223,10 @@
|
||||
"@babel/types" "^7.28.0"
|
||||
debug "^4.3.1"
|
||||
|
||||
"@babel/types@^7.26.9", "@babel/types@^7.27.1", "@babel/types@^7.27.3", "@babel/types@^7.27.6", "@babel/types@^7.28.0":
|
||||
version "7.28.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.28.1.tgz#2aaf3c10b31ba03a77ac84f52b3912a0edef4cf9"
|
||||
integrity sha512-x0LvFTekgSX+83TI28Y9wYPUfzrnl2aT5+5QLnO6v7mSJYtEEevuDRN0F0uSHRk1G1IWZC43o00Y0xDDrpBGPQ==
|
||||
"@babel/types@^7.26.9", "@babel/types@^7.27.1", "@babel/types@^7.27.3", "@babel/types@^7.28.0", "@babel/types@^7.28.2":
|
||||
version "7.28.2"
|
||||
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.28.2.tgz#da9db0856a9a88e0a13b019881d7513588cf712b"
|
||||
integrity sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==
|
||||
dependencies:
|
||||
"@babel/helper-string-parser" "^7.27.1"
|
||||
"@babel/helper-validator-identifier" "^7.27.1"
|
||||
@@ -413,6 +413,14 @@
|
||||
"@monogrid/gainmap-js" "^3.1.0"
|
||||
lit "^3.2.1"
|
||||
|
||||
"@guolao/vue-monaco-editor@^1.5.5":
|
||||
version "1.5.5"
|
||||
resolved "https://registry.yarnpkg.com/@guolao/vue-monaco-editor/-/vue-monaco-editor-1.5.5.tgz#c29fb7ba6e93763d4efd2dc06a12bb3b687363f7"
|
||||
integrity sha512-NFGImQ8dBYj6ehIxy1DngPRkctB9b6GbxvCm6aXZztNsgm/TtM4u+YM9ZwZHQPlXt7a4IODXoKCcTYEVycBSyA==
|
||||
dependencies:
|
||||
"@monaco-editor/loader" "^1.5.0"
|
||||
vue-demi latest
|
||||
|
||||
"@img/sharp-darwin-arm64@0.33.5":
|
||||
version "0.33.5"
|
||||
resolved "https://registry.yarnpkg.com/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz#ef5b5a07862805f1e8145a377c8ba6e98813ca08"
|
||||
@@ -623,6 +631,13 @@
|
||||
resolved "https://registry.yarnpkg.com/@mdi/svg/-/svg-7.4.47.tgz#f8e5516aae129764a76d1bb2f27e55bee03e6e90"
|
||||
integrity sha512-WQ2gDll12T9WD34fdRFgQVgO8bag3gavrAgJ0frN4phlwdJARpE6gO1YvLEMJR0KKgoc+/Ea/A0Pp11I00xBvw==
|
||||
|
||||
"@monaco-editor/loader@^1.5.0":
|
||||
version "1.5.0"
|
||||
resolved "https://registry.yarnpkg.com/@monaco-editor/loader/-/loader-1.5.0.tgz#dcdbc7fe7e905690fb449bed1c251769f325c55d"
|
||||
integrity sha512-hKoGSM+7aAc7eRTRjpqAZucPmoNOC4UUbknb/VNoTkEIkCPhqV8LfbsgM1webRM7S/z21eHEx9Fkwx8Z/C/+Xw==
|
||||
dependencies:
|
||||
state-local "^1.0.6"
|
||||
|
||||
"@monogrid/gainmap-js@^3.1.0":
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@monogrid/gainmap-js/-/gainmap-js-3.1.0.tgz#4ac1f88abd6affdf0b51d79318109183b499c502"
|
||||
@@ -642,9 +657,9 @@
|
||||
socks-proxy-agent "^8.0.3"
|
||||
|
||||
"@npmcli/arborist@^9.0.0":
|
||||
version "9.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@npmcli/arborist/-/arborist-9.1.2.tgz#a604827936d47c581424d7de1665575e47c0ae8d"
|
||||
integrity sha512-KIuQc8TuMTcL8OTVmOTdVIXmkDFFOHmVlVd94N9wwHjuOA2ZyNsoJPS50Q/irdkS3LF/9BiIcxSIV/ukSjqO6g==
|
||||
version "9.1.3"
|
||||
resolved "https://registry.yarnpkg.com/@npmcli/arborist/-/arborist-9.1.3.tgz#a8dac0c357af78b9c834210c9017f41289413c19"
|
||||
integrity sha512-PvwtZD1dipP5VByHyWX28tZfan1AkfBLenJTgr0rDdEbdovZc06Z5PHdGb5SEeN7EERl68wFH8lq6WvuUHmgrw==
|
||||
dependencies:
|
||||
"@isaacs/string-locale-compare" "^1.1.0"
|
||||
"@npmcli/fs" "^4.0.0"
|
||||
@@ -796,9 +811,9 @@
|
||||
integrity sha512-3FL3mnMbPu0muGOCaKAhhFEYmqv9eTfPSJRJmANrCwtgK8VuxpsZDGK+m0LYAGoyO8+0j5uRe4PeyPDK1yA/hA==
|
||||
|
||||
"@rolldown/pluginutils@^1.0.0-beta.21":
|
||||
version "1.0.0-beta.28"
|
||||
resolved "https://registry.yarnpkg.com/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.28.tgz#3a5887a3cd4b556afedf1f4a282fd061e2bb2524"
|
||||
integrity sha512-fe3/1HZ3qJmXvkGv1kacKq2b+x9gbcyF1hnmLBVrRFEQWoOcRapQjXf8+hgyxI0EJAbnKEtrp5yhohQCFCjycw==
|
||||
version "1.0.0-beta.29"
|
||||
resolved "https://registry.yarnpkg.com/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.29.tgz#f8fc9a8788757dccba0d3b7fee93183621773d4c"
|
||||
integrity sha512-NIJgOsMjbxAXvoGq/X0gD7VPMQ8j9g0BiDaNjVNVjvl+iKXxL3Jre0v31RmBYeLEmkbj2s02v8vFTbUXi5XS2Q==
|
||||
|
||||
"@rollup/rollup-android-arm-eabi@4.45.1":
|
||||
version "4.45.1"
|
||||
@@ -986,6 +1001,11 @@
|
||||
dependencies:
|
||||
undici-types "~6.21.0"
|
||||
|
||||
"@types/pako@^2.0.3":
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/pako/-/pako-2.0.3.tgz#b6993334f3af27c158f3fe0dfeeba987c578afb1"
|
||||
integrity sha512-bq0hMV9opAcrmE0Byyo0fY3Ew4tgOevJmQ9grUhpXQhYfyLJ1Kqg3P33JT5fdbT2AjeAjR51zqqVjAL/HMkx7Q==
|
||||
|
||||
"@types/stats.js@*":
|
||||
version "0.17.4"
|
||||
resolved "https://registry.yarnpkg.com/@types/stats.js/-/stats.js-0.17.4.tgz#1933e5ff153a23c7664487833198d685c22e791e"
|
||||
@@ -1083,47 +1103,47 @@
|
||||
"@babel/parser" "^7.26.9"
|
||||
"@vue/compiler-sfc" "^3.5.13"
|
||||
|
||||
"@vue/compiler-core@3.5.17":
|
||||
version "3.5.17"
|
||||
resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.5.17.tgz#23d291bd01b863da3ef2e26e7db84d8e01a9b4c5"
|
||||
integrity sha512-Xe+AittLbAyV0pabcN7cP7/BenRBNcteM4aSDCtRvGw0d9OL+HG1u/XHLY/kt1q4fyMeZYXyIYrsHuPSiDPosA==
|
||||
"@vue/compiler-core@3.5.18":
|
||||
version "3.5.18"
|
||||
resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.5.18.tgz#521a138cdd970d9bfd27e42168d12f77a04b2074"
|
||||
integrity sha512-3slwjQrrV1TO8MoXgy3aynDQ7lslj5UqDxuHnrzHtpON5CBinhWjJETciPngpin/T3OuW3tXUf86tEurusnztw==
|
||||
dependencies:
|
||||
"@babel/parser" "^7.27.5"
|
||||
"@vue/shared" "3.5.17"
|
||||
"@babel/parser" "^7.28.0"
|
||||
"@vue/shared" "3.5.18"
|
||||
entities "^4.5.0"
|
||||
estree-walker "^2.0.2"
|
||||
source-map-js "^1.2.1"
|
||||
|
||||
"@vue/compiler-dom@3.5.17", "@vue/compiler-dom@^3.5.0":
|
||||
version "3.5.17"
|
||||
resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.5.17.tgz#7bc19a20e23b670243a64b47ce3a890239b870be"
|
||||
integrity sha512-+2UgfLKoaNLhgfhV5Ihnk6wB4ljyW1/7wUIog2puUqajiC29Lp5R/IKDdkebh9jTbTogTbsgB+OY9cEWzG95JQ==
|
||||
"@vue/compiler-dom@3.5.18", "@vue/compiler-dom@^3.5.0":
|
||||
version "3.5.18"
|
||||
resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.5.18.tgz#e13504492c3061ec5bbe6a2e789f15261d4f03a7"
|
||||
integrity sha512-RMbU6NTU70++B1JyVJbNbeFkK+A+Q7y9XKE2EM4NLGm2WFR8x9MbAtWxPPLdm0wUkuZv9trpwfSlL6tjdIa1+A==
|
||||
dependencies:
|
||||
"@vue/compiler-core" "3.5.17"
|
||||
"@vue/shared" "3.5.17"
|
||||
"@vue/compiler-core" "3.5.18"
|
||||
"@vue/shared" "3.5.18"
|
||||
|
||||
"@vue/compiler-sfc@3.5.17", "@vue/compiler-sfc@^3.5.13":
|
||||
version "3.5.17"
|
||||
resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-3.5.17.tgz#c518871276e26593612bdab36f3f5bcd053b13bf"
|
||||
integrity sha512-rQQxbRJMgTqwRugtjw0cnyQv9cP4/4BxWfTdRBkqsTfLOHWykLzbOc3C4GGzAmdMDxhzU/1Ija5bTjMVrddqww==
|
||||
"@vue/compiler-sfc@3.5.18", "@vue/compiler-sfc@^3.5.13":
|
||||
version "3.5.18"
|
||||
resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-3.5.18.tgz#ba1e849561337d809937994cdaf900539542eeca"
|
||||
integrity sha512-5aBjvGqsWs+MoxswZPoTB9nSDb3dhd1x30xrrltKujlCxo48j8HGDNj3QPhF4VIS0VQDUrA1xUfp2hEa+FNyXA==
|
||||
dependencies:
|
||||
"@babel/parser" "^7.27.5"
|
||||
"@vue/compiler-core" "3.5.17"
|
||||
"@vue/compiler-dom" "3.5.17"
|
||||
"@vue/compiler-ssr" "3.5.17"
|
||||
"@vue/shared" "3.5.17"
|
||||
"@babel/parser" "^7.28.0"
|
||||
"@vue/compiler-core" "3.5.18"
|
||||
"@vue/compiler-dom" "3.5.18"
|
||||
"@vue/compiler-ssr" "3.5.18"
|
||||
"@vue/shared" "3.5.18"
|
||||
estree-walker "^2.0.2"
|
||||
magic-string "^0.30.17"
|
||||
postcss "^8.5.6"
|
||||
source-map-js "^1.2.1"
|
||||
|
||||
"@vue/compiler-ssr@3.5.17":
|
||||
version "3.5.17"
|
||||
resolved "https://registry.yarnpkg.com/@vue/compiler-ssr/-/compiler-ssr-3.5.17.tgz#14ba3b7bba6e0e1fd02002316263165a5d1046c7"
|
||||
integrity sha512-hkDbA0Q20ZzGgpj5uZjb9rBzQtIHLS78mMilwrlpWk2Ep37DYntUz0PonQ6kr113vfOEdM+zTBuJDaceNIW0tQ==
|
||||
"@vue/compiler-ssr@3.5.18":
|
||||
version "3.5.18"
|
||||
resolved "https://registry.yarnpkg.com/@vue/compiler-ssr/-/compiler-ssr-3.5.18.tgz#aecde0b0bff268a9c9014ba66799307c4a784328"
|
||||
integrity sha512-xM16Ak7rSWHkM3m22NlmcdIM+K4BMyFARAfV9hYFl+SFuRzrZ3uGMNW05kA5pmeMa0X9X963Kgou7ufdbpOP9g==
|
||||
dependencies:
|
||||
"@vue/compiler-dom" "3.5.17"
|
||||
"@vue/shared" "3.5.17"
|
||||
"@vue/compiler-dom" "3.5.18"
|
||||
"@vue/shared" "3.5.18"
|
||||
|
||||
"@vue/compiler-vue2@^2.7.16":
|
||||
version "2.7.16"
|
||||
@@ -1133,10 +1153,10 @@
|
||||
de-indent "^1.0.2"
|
||||
he "^1.2.0"
|
||||
|
||||
"@vue/language-core@3.0.3":
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@vue/language-core/-/language-core-3.0.3.tgz#f5a24407681693dc352901d6241b370251d7eab1"
|
||||
integrity sha512-I9wY0ULMN9tMSua+2C7g+ez1cIziVMUzIHlDYGSl2rtru3Eh4sXj95vZ+4GBuXwwPnEmYfzSApVbXiVbI8V5Gg==
|
||||
"@vue/language-core@3.0.4":
|
||||
version "3.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@vue/language-core/-/language-core-3.0.4.tgz#aa080a96d385ad8e23a801265cf80225ac4be414"
|
||||
integrity sha512-BvueED4LfBCSNH66eeUQk37MQCb7hjdezzGgxniM0LbriW53AJIyLorgshAtStmjfsAuOCcTl/c1b+nz/ye8xQ==
|
||||
dependencies:
|
||||
"@volar/language-core" "2.4.20"
|
||||
"@vue/compiler-dom" "^3.5.0"
|
||||
@@ -1147,43 +1167,43 @@
|
||||
path-browserify "^1.0.1"
|
||||
picomatch "^4.0.2"
|
||||
|
||||
"@vue/reactivity@3.5.17":
|
||||
version "3.5.17"
|
||||
resolved "https://registry.yarnpkg.com/@vue/reactivity/-/reactivity-3.5.17.tgz#169b5dcf96c7f23788e5ed9745ec8a7227f2125e"
|
||||
integrity sha512-l/rmw2STIscWi7SNJp708FK4Kofs97zc/5aEPQh4bOsReD/8ICuBcEmS7KGwDj5ODQLYWVN2lNibKJL1z5b+Lw==
|
||||
"@vue/reactivity@3.5.18":
|
||||
version "3.5.18"
|
||||
resolved "https://registry.yarnpkg.com/@vue/reactivity/-/reactivity-3.5.18.tgz#fe32166e3938832c54b4134e60e9b58ca7d9bdb4"
|
||||
integrity sha512-x0vPO5Imw+3sChLM5Y+B6G1zPjwdOri9e8V21NnTnlEvkxatHEH5B5KEAJcjuzQ7BsjGrKtfzuQ5eQwXh8HXBg==
|
||||
dependencies:
|
||||
"@vue/shared" "3.5.17"
|
||||
"@vue/shared" "3.5.18"
|
||||
|
||||
"@vue/runtime-core@3.5.17":
|
||||
version "3.5.17"
|
||||
resolved "https://registry.yarnpkg.com/@vue/runtime-core/-/runtime-core-3.5.17.tgz#b17bd41e13011e85e9b1025545292d43f5512730"
|
||||
integrity sha512-QQLXa20dHg1R0ri4bjKeGFKEkJA7MMBxrKo2G+gJikmumRS7PTD4BOU9FKrDQWMKowz7frJJGqBffYMgQYS96Q==
|
||||
"@vue/runtime-core@3.5.18":
|
||||
version "3.5.18"
|
||||
resolved "https://registry.yarnpkg.com/@vue/runtime-core/-/runtime-core-3.5.18.tgz#9e9ae8b9491548b53d0cea2bf25746d27c52e191"
|
||||
integrity sha512-DUpHa1HpeOQEt6+3nheUfqVXRog2kivkXHUhoqJiKR33SO4x+a5uNOMkV487WPerQkL0vUuRvq/7JhRgLW3S+w==
|
||||
dependencies:
|
||||
"@vue/reactivity" "3.5.17"
|
||||
"@vue/shared" "3.5.17"
|
||||
"@vue/reactivity" "3.5.18"
|
||||
"@vue/shared" "3.5.18"
|
||||
|
||||
"@vue/runtime-dom@3.5.17":
|
||||
version "3.5.17"
|
||||
resolved "https://registry.yarnpkg.com/@vue/runtime-dom/-/runtime-dom-3.5.17.tgz#8e325e29cd03097fe179032fc8df384a426fc83a"
|
||||
integrity sha512-8El0M60TcwZ1QMz4/os2MdlQECgGoVHPuLnQBU3m9h3gdNRW9xRmI8iLS4t/22OQlOE6aJvNNlBiCzPHur4H9g==
|
||||
"@vue/runtime-dom@3.5.18":
|
||||
version "3.5.18"
|
||||
resolved "https://registry.yarnpkg.com/@vue/runtime-dom/-/runtime-dom-3.5.18.tgz#1150952d1048b5822e4f1dd8aed24665cbb22107"
|
||||
integrity sha512-YwDj71iV05j4RnzZnZtGaXwPoUWeRsqinblgVJwR8XTXYZ9D5PbahHQgsbmzUvCWNF6x7siQ89HgnX5eWkr3mw==
|
||||
dependencies:
|
||||
"@vue/reactivity" "3.5.17"
|
||||
"@vue/runtime-core" "3.5.17"
|
||||
"@vue/shared" "3.5.17"
|
||||
"@vue/reactivity" "3.5.18"
|
||||
"@vue/runtime-core" "3.5.18"
|
||||
"@vue/shared" "3.5.18"
|
||||
csstype "^3.1.3"
|
||||
|
||||
"@vue/server-renderer@3.5.17":
|
||||
version "3.5.17"
|
||||
resolved "https://registry.yarnpkg.com/@vue/server-renderer/-/server-renderer-3.5.17.tgz#9b8fd6a40a3d55322509fafe78ac841ede649fbe"
|
||||
integrity sha512-BOHhm8HalujY6lmC3DbqF6uXN/K00uWiEeF22LfEsm9Q93XeJ/plHTepGwf6tqFcF7GA5oGSSAAUock3VvzaCA==
|
||||
"@vue/server-renderer@3.5.18":
|
||||
version "3.5.18"
|
||||
resolved "https://registry.yarnpkg.com/@vue/server-renderer/-/server-renderer-3.5.18.tgz#e9fa267b95b3a1d8cddca762377e5de2ae9122bd"
|
||||
integrity sha512-PvIHLUoWgSbDG7zLHqSqaCoZvHi6NNmfVFOqO+OnwvqMz/tqQr3FuGWS8ufluNddk7ZLBJYMrjcw1c6XzR12mA==
|
||||
dependencies:
|
||||
"@vue/compiler-ssr" "3.5.17"
|
||||
"@vue/shared" "3.5.17"
|
||||
"@vue/compiler-ssr" "3.5.18"
|
||||
"@vue/shared" "3.5.18"
|
||||
|
||||
"@vue/shared@3.5.17", "@vue/shared@^3.5.0", "@vue/shared@^3.5.13":
|
||||
version "3.5.17"
|
||||
resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.5.17.tgz#e8b3a41f0be76499882a89e8ed40d86a70fa4b70"
|
||||
integrity sha512-CabR+UN630VnsJO/jHWYBC1YVXyMq94KKp6iF5MQgZJs5I8cmjw6oVMO1oDbtBkENSHSSn/UadWlW/OAgdmKrg==
|
||||
"@vue/shared@3.5.18", "@vue/shared@^3.5.0", "@vue/shared@^3.5.13":
|
||||
version "3.5.18"
|
||||
resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.5.18.tgz#529f24a88d3ed678d50fd5c07455841fbe8ac95e"
|
||||
integrity sha512-cZy8Dq+uuIXbxCZpuLd2GJdeSO/lIzIspC2WtkqIpje5QyFbvLaI5wZtdUjLHjGZrlVX6GilejatWwVYYRc8tA==
|
||||
|
||||
"@vue/tsconfig@^0.7.0":
|
||||
version "0.7.0"
|
||||
@@ -1242,6 +1262,14 @@ ansi-styles@^6.1.0, ansi-styles@^6.2.1:
|
||||
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5"
|
||||
integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==
|
||||
|
||||
anymatch@~3.1.2:
|
||||
version "3.1.3"
|
||||
resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e"
|
||||
integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==
|
||||
dependencies:
|
||||
normalize-path "^3.0.0"
|
||||
picomatch "^2.0.4"
|
||||
|
||||
argparse@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38"
|
||||
@@ -1268,6 +1296,11 @@ bin-links@^5.0.0:
|
||||
read-cmd-shim "^5.0.0"
|
||||
write-file-atomic "^6.0.0"
|
||||
|
||||
binary-extensions@^2.0.0:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522"
|
||||
integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==
|
||||
|
||||
bl@^4.1.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a"
|
||||
@@ -1284,6 +1317,13 @@ brace-expansion@^2.0.1:
|
||||
dependencies:
|
||||
balanced-match "^1.0.0"
|
||||
|
||||
braces@~3.0.2:
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789"
|
||||
integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==
|
||||
dependencies:
|
||||
fill-range "^7.1.1"
|
||||
|
||||
browserslist@^4.24.0:
|
||||
version "4.25.1"
|
||||
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.25.1.tgz#ba9e8e6f298a1d86f829c9b975e07948967bb111"
|
||||
@@ -1351,6 +1391,21 @@ chalk@^4.1.0:
|
||||
ansi-styles "^4.1.0"
|
||||
supports-color "^7.1.0"
|
||||
|
||||
chokidar@^3.6.0:
|
||||
version "3.6.0"
|
||||
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b"
|
||||
integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==
|
||||
dependencies:
|
||||
anymatch "~3.1.2"
|
||||
braces "~3.0.2"
|
||||
glob-parent "~5.1.2"
|
||||
is-binary-path "~2.1.0"
|
||||
is-glob "~4.0.1"
|
||||
normalize-path "~3.0.0"
|
||||
readdirp "~3.6.0"
|
||||
optionalDependencies:
|
||||
fsevents "~2.3.2"
|
||||
|
||||
chownr@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece"
|
||||
@@ -1502,9 +1557,9 @@ eastasianwidth@^0.2.0:
|
||||
integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==
|
||||
|
||||
electron-to-chromium@^1.5.173:
|
||||
version "1.5.187"
|
||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.187.tgz#8c58854e065962351dc87e95614dd78d50425966"
|
||||
integrity sha512-cl5Jc9I0KGUoOoSbxvTywTa40uspGJt/BDBoDLoxJRSBpWh4FFXBsjNRHfQrONsV/OoEjDfHUmZQa2d6Ze4YgA==
|
||||
version "1.5.191"
|
||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.191.tgz#8ae49a471447b1ceaf1d4d183a9000082f52363c"
|
||||
integrity sha512-xcwe9ELcuxYLUFqZZxL19Z6HVKcvNkIwhbHUz7L3us6u12yR+7uY89dSl570f/IqNthx8dAw3tojG7i4Ni4tDA==
|
||||
|
||||
emoji-regex@^8.0.0:
|
||||
version "8.0.0"
|
||||
@@ -1610,6 +1665,13 @@ fflate@~0.8.2:
|
||||
resolved "https://registry.yarnpkg.com/fflate/-/fflate-0.8.2.tgz#fc8631f5347812ad6028bbe4a2308b2792aa1dea"
|
||||
integrity sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==
|
||||
|
||||
fill-range@^7.1.1:
|
||||
version "7.1.1"
|
||||
resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292"
|
||||
integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==
|
||||
dependencies:
|
||||
to-regex-range "^5.0.1"
|
||||
|
||||
foreground-child@^3.1.0, foreground-child@^3.3.1:
|
||||
version "3.3.1"
|
||||
resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.3.1.tgz#32e8e9ed1b68a3497befb9ac2b6adf92a638576f"
|
||||
@@ -1618,6 +1680,15 @@ foreground-child@^3.1.0, foreground-child@^3.3.1:
|
||||
cross-spawn "^7.0.6"
|
||||
signal-exit "^4.0.1"
|
||||
|
||||
fs-extra@^11.3.0:
|
||||
version "11.3.0"
|
||||
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-11.3.0.tgz#0daced136bbaf65a555a326719af931adc7a314d"
|
||||
integrity sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==
|
||||
dependencies:
|
||||
graceful-fs "^4.2.0"
|
||||
jsonfile "^6.0.1"
|
||||
universalify "^2.0.0"
|
||||
|
||||
fs-minipass@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb"
|
||||
@@ -1659,6 +1730,13 @@ gensync@^1.0.0-beta.2:
|
||||
resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0"
|
||||
integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==
|
||||
|
||||
glob-parent@~5.1.2:
|
||||
version "5.1.2"
|
||||
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
|
||||
integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
|
||||
dependencies:
|
||||
is-glob "^4.0.1"
|
||||
|
||||
glob@^10.2.2:
|
||||
version "10.4.5"
|
||||
resolved "https://registry.yarnpkg.com/glob/-/glob-10.4.5.tgz#f4d9f0b90ffdbab09c9d77f5f29b4262517b0956"
|
||||
@@ -1683,7 +1761,7 @@ glob@^11.0.0:
|
||||
package-json-from-dist "^1.0.0"
|
||||
path-scurry "^2.0.0"
|
||||
|
||||
graceful-fs@^4.2.6:
|
||||
graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.6:
|
||||
version "4.2.11"
|
||||
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3"
|
||||
integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==
|
||||
@@ -1738,12 +1816,12 @@ ieee754@^1.1.13, ieee754@^1.2.1:
|
||||
resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
|
||||
integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
|
||||
|
||||
ignore-walk@^7.0.0:
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-7.0.0.tgz#8350e475cf4375969c12eb49618b3fd9cca6704f"
|
||||
integrity sha512-T4gbf83A4NH95zvhVYZc+qWocBBGlpzUXLPGurJggw/WIOwicfXJChLDP/iBZnN5WqROSu5Bm3hhle4z8a8YGQ==
|
||||
ignore-walk@^8.0.0:
|
||||
version "8.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-8.0.0.tgz#380c173badc3a18c57ff33440753f0052f572b14"
|
||||
integrity sha512-FCeMZT4NiRQGh+YkeKMtWrOmBgWjHjMJ26WQWrRQyoyzqevdaGSakUaJW5xQYmjLlUVk2qUnCjYVBax9EKKg8A==
|
||||
dependencies:
|
||||
minimatch "^9.0.0"
|
||||
minimatch "^10.0.3"
|
||||
|
||||
immediate@~3.0.5:
|
||||
version "3.0.6"
|
||||
@@ -1796,21 +1874,45 @@ is-arrayish@^0.3.1:
|
||||
resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03"
|
||||
integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==
|
||||
|
||||
is-binary-path@~2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09"
|
||||
integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==
|
||||
dependencies:
|
||||
binary-extensions "^2.0.0"
|
||||
|
||||
is-buffer@^1.0.2:
|
||||
version "1.1.6"
|
||||
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
|
||||
integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==
|
||||
|
||||
is-extglob@^2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
|
||||
integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==
|
||||
|
||||
is-fullwidth-code-point@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d"
|
||||
integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==
|
||||
|
||||
is-glob@^4.0.1, is-glob@~4.0.1:
|
||||
version "4.0.3"
|
||||
resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084"
|
||||
integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==
|
||||
dependencies:
|
||||
is-extglob "^2.1.1"
|
||||
|
||||
is-interactive@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-interactive/-/is-interactive-1.0.0.tgz#cea6e6ae5c870a7b0a0004070b7b587e0252912e"
|
||||
integrity sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==
|
||||
|
||||
is-number@^7.0.0:
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
|
||||
integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
|
||||
|
||||
is-promise@^2.1.0:
|
||||
version "2.2.2"
|
||||
resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.2.2.tgz#39ab959ccbf9a774cf079f7b40c7a26f763135f1"
|
||||
@@ -1847,6 +1949,11 @@ jackspeak@^4.1.1:
|
||||
dependencies:
|
||||
"@isaacs/cliui" "^8.0.2"
|
||||
|
||||
js-base64@^3.7.7:
|
||||
version "3.7.7"
|
||||
resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-3.7.7.tgz#e51b84bf78fbf5702b9541e2cb7bfcb893b43e79"
|
||||
integrity sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw==
|
||||
|
||||
js-tokens@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
|
||||
@@ -1889,6 +1996,15 @@ json5@^2.2.3:
|
||||
resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283"
|
||||
integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==
|
||||
|
||||
jsonfile@^6.0.1:
|
||||
version "6.1.0"
|
||||
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae"
|
||||
integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==
|
||||
dependencies:
|
||||
universalify "^2.0.0"
|
||||
optionalDependencies:
|
||||
graceful-fs "^4.1.6"
|
||||
|
||||
jsonparse@^1.3.1:
|
||||
version "1.3.1"
|
||||
resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280"
|
||||
@@ -2105,6 +2221,11 @@ mkdirp@^3.0.1:
|
||||
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-3.0.1.tgz#e44e4c5607fb279c168241713cc6e0fea9adcb50"
|
||||
integrity sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==
|
||||
|
||||
monaco-editor@^0.52.2:
|
||||
version "0.52.2"
|
||||
resolved "https://registry.yarnpkg.com/monaco-editor/-/monaco-editor-0.52.2.tgz#53c75a6fcc6802684e99fd1b2700299857002205"
|
||||
integrity sha512-GEQWEZmfkOGLdd3XK8ryrfWz3AIP8YymVXiPHEdewrUq7mh0qrKrfHLNCXcbB6sTnMLnOZ3ztSiKcciFUkIJwQ==
|
||||
|
||||
ms@^2.1.3:
|
||||
version "2.1.3"
|
||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
|
||||
@@ -2186,6 +2307,11 @@ nopt@^8.0.0:
|
||||
dependencies:
|
||||
abbrev "^3.0.0"
|
||||
|
||||
normalize-path@^3.0.0, normalize-path@~3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
|
||||
integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
|
||||
|
||||
npm-bundled@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-4.0.0.tgz#f5b983f053fe7c61566cf07241fab2d4e9d513d3"
|
||||
@@ -2216,11 +2342,11 @@ npm-package-arg@^12.0.0:
|
||||
validate-npm-package-name "^6.0.0"
|
||||
|
||||
npm-packlist@^10.0.0:
|
||||
version "10.0.0"
|
||||
resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-10.0.0.tgz#35634f0a90f84a811ebdf565eb78d2b36252888c"
|
||||
integrity sha512-rht9U6nS8WOBDc53eipZNPo5qkAV4X2rhKE2Oj1DYUQ3DieXfj0mKkVmjnf3iuNdtMd8WfLdi2L6ASkD/8a+Kg==
|
||||
version "10.0.1"
|
||||
resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-10.0.1.tgz#236853e6ebff06e70fedd7a6a054f553afe19023"
|
||||
integrity sha512-vaC03b2PqJA6QqmwHi1jNU8fAPXEnnyv4j/W4PVfgm24C4/zZGSVut3z0YUeN0WIFCo1oGOL02+6LbvFK7JL4Q==
|
||||
dependencies:
|
||||
ignore-walk "^7.0.0"
|
||||
ignore-walk "^8.0.0"
|
||||
|
||||
npm-pick-manifest@^10.0.0:
|
||||
version "10.0.0"
|
||||
@@ -2282,7 +2408,7 @@ ora@^5.4.1:
|
||||
strip-ansi "^6.0.0"
|
||||
wcwidth "^1.0.1"
|
||||
|
||||
p-map@^7.0.2:
|
||||
p-map@^7.0.2, p-map@^7.0.3:
|
||||
version "7.0.3"
|
||||
resolved "https://registry.yarnpkg.com/p-map/-/p-map-7.0.3.tgz#7ac210a2d36f81ec28b736134810f7ba4418cdb6"
|
||||
integrity sha512-VkndIv2fIB99swvQoA65bm+fsmt6UNdGeIB0oxBs+WhAhdh08QA04JXpI7rbB9r08/nkbysKoya9rtDERYOYMA==
|
||||
@@ -2315,6 +2441,11 @@ pacote@^21.0.0:
|
||||
ssri "^12.0.0"
|
||||
tar "^6.1.11"
|
||||
|
||||
pako@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/pako/-/pako-2.1.0.tgz#266cc37f98c7d883545d11335c00fbd4062c9a86"
|
||||
integrity sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==
|
||||
|
||||
parent-module@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2"
|
||||
@@ -2372,7 +2503,12 @@ picocolors@^1.1.1:
|
||||
resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b"
|
||||
integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==
|
||||
|
||||
picomatch@^4.0.2:
|
||||
picomatch@^2.0.4, picomatch@^2.2.1:
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
|
||||
integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
|
||||
|
||||
picomatch@^4.0.2, picomatch@^4.0.3:
|
||||
version "4.0.3"
|
||||
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.3.tgz#796c76136d1eead715db1e7bad785dedd695a042"
|
||||
integrity sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==
|
||||
@@ -2440,6 +2576,13 @@ property-graph@^3.0.0:
|
||||
resolved "https://registry.yarnpkg.com/property-graph/-/property-graph-3.0.0.tgz#c3187a0389a7ec56b8c9207fe3867b2ba3d1e6df"
|
||||
integrity sha512-TnzxUsttmGtw+OiU0LDw+0FlMbJ8vV8pOjyDI7+Kdni4Tj0hW5BFh7TatQu7Y68hcvvFmiFOHilKShsA4R82fA==
|
||||
|
||||
pyodide@^0.28.0:
|
||||
version "0.28.0"
|
||||
resolved "https://registry.yarnpkg.com/pyodide/-/pyodide-0.28.0.tgz#43c50db977e28eba83da84a326c32537bc713460"
|
||||
integrity sha512-QML/Gh8eu50q5zZKLNpW6rgS0XUdK+94OSL54AUSKV8eJAxgwZrMebqj+CyM0EbF3EUX8JFJU3ryaxBViHammQ==
|
||||
dependencies:
|
||||
ws "^8.5.0"
|
||||
|
||||
read-cmd-shim@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/read-cmd-shim/-/read-cmd-shim-5.0.0.tgz#6e5450492187a0749f6c80dcbef0debc1117acca"
|
||||
@@ -2462,6 +2605,13 @@ readable-stream@^3.4.0:
|
||||
string_decoder "^1.1.1"
|
||||
util-deprecate "^1.0.1"
|
||||
|
||||
readdirp@~3.6.0:
|
||||
version "3.6.0"
|
||||
resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7"
|
||||
integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==
|
||||
dependencies:
|
||||
picomatch "^2.2.1"
|
||||
|
||||
resolve-from@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
|
||||
@@ -2682,6 +2832,11 @@ ssri@^12.0.0:
|
||||
dependencies:
|
||||
minipass "^7.0.3"
|
||||
|
||||
state-local@^1.0.6:
|
||||
version "1.0.7"
|
||||
resolved "https://registry.yarnpkg.com/state-local/-/state-local-1.0.7.tgz#da50211d07f05748d53009bee46307a37db386d5"
|
||||
integrity sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==
|
||||
|
||||
"string-width-cjs@npm:string-width@^4.2.0":
|
||||
version "4.2.3"
|
||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
|
||||
@@ -2783,10 +2938,9 @@ three-mesh-bvh@^0.9.0:
|
||||
resolved "https://registry.yarnpkg.com/three-mesh-bvh/-/three-mesh-bvh-0.9.1.tgz#fa6db25f14bb4d2453f15c926f5eb9eba1811168"
|
||||
integrity sha512-WNT+m9jGQgtp4YdtwEnl4oFylNVifRf7iphlwWdJ4bJu7oNkY0xHIyntep9OzHuR1hpe/pyAP840gB/EsYDJfg==
|
||||
|
||||
"three-orientation-gizmo@https://github.com/jrj2211/three-orientation-gizmo":
|
||||
"three-orientation-gizmo@git+https://github.com/jrj2211/three-orientation-gizmo.git":
|
||||
version "1.1.0"
|
||||
uid "000281f0559c316f72cdd23a1885d63ae6901095"
|
||||
resolved "https://github.com/jrj2211/three-orientation-gizmo#000281f0559c316f72cdd23a1885d63ae6901095"
|
||||
resolved "git+https://github.com/jrj2211/three-orientation-gizmo.git#000281f0559c316f72cdd23a1885d63ae6901095"
|
||||
dependencies:
|
||||
three "^0.125.0"
|
||||
|
||||
@@ -2808,6 +2962,13 @@ tinyglobby@^0.2.12, tinyglobby@^0.2.14:
|
||||
fdir "^6.4.4"
|
||||
picomatch "^4.0.2"
|
||||
|
||||
to-regex-range@^5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
|
||||
integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
|
||||
dependencies:
|
||||
is-number "^7.0.0"
|
||||
|
||||
treeverse@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/treeverse/-/treeverse-3.0.0.tgz#dd82de9eb602115c6ebd77a574aae67003cb48c8"
|
||||
@@ -2856,6 +3017,11 @@ unique-slug@^5.0.0:
|
||||
dependencies:
|
||||
imurmurhash "^0.1.4"
|
||||
|
||||
universalify@^2.0.0:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.1.tgz#168efc2180964e6386d061e094df61afe239b18d"
|
||||
integrity sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==
|
||||
|
||||
update-browserslist-db@^1.1.3:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz#348377dd245216f9e7060ff50b15a1b740b75420"
|
||||
@@ -2878,18 +3044,29 @@ validate-npm-package-license@^3.0.4:
|
||||
spdx-expression-parse "^3.0.0"
|
||||
|
||||
validate-npm-package-name@^6.0.0:
|
||||
version "6.0.1"
|
||||
resolved "https://registry.yarnpkg.com/validate-npm-package-name/-/validate-npm-package-name-6.0.1.tgz#7b928e5fe23996045a6de5b5a22eedb3611264dd"
|
||||
integrity sha512-OaI//3H0J7ZkR1OqlhGA8cA+Cbk/2xFOQpJOt5+s27/ta9eZwpeervh4Mxh4w0im/kdgktowaqVNR7QOrUd7Yg==
|
||||
version "6.0.2"
|
||||
resolved "https://registry.yarnpkg.com/validate-npm-package-name/-/validate-npm-package-name-6.0.2.tgz#4e8d2c4d939975a73dd1b7a65e8f08d44c85df96"
|
||||
integrity sha512-IUoow1YUtvoBBC06dXs8bR8B9vuA3aJfmQNKMoaPG/OFsPmoQvw8xh+6Ye25Gx9DQhoEom3Pcu9MKHerm/NpUQ==
|
||||
|
||||
vite-plugin-static-copy@^3.1.1:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/vite-plugin-static-copy/-/vite-plugin-static-copy-3.1.1.tgz#25d6f52c9a760d2d2e84d0803a37e3310aed644a"
|
||||
integrity sha512-oR53SkL5cX4KT1t18E/xU50vJDo0N8oaHza4EMk0Fm+2/u6nQivxavOfrDk3udWj+dizRizB/QnBvJOOQrTTAQ==
|
||||
dependencies:
|
||||
chokidar "^3.6.0"
|
||||
fs-extra "^11.3.0"
|
||||
p-map "^7.0.3"
|
||||
picocolors "^1.1.1"
|
||||
tinyglobby "^0.2.14"
|
||||
|
||||
vite@^7.0.0:
|
||||
version "7.0.5"
|
||||
resolved "https://registry.yarnpkg.com/vite/-/vite-7.0.5.tgz#deb2d3b777378f6d3e47c3d41b59f3c93f485738"
|
||||
integrity sha512-1mncVwJxy2C9ThLwz0+2GKZyEXuC3MyWtAAlNftlZZXZDP3AJt5FmwcMit/IGGaNZ8ZOB2BNO/HFUB+CpN0NQw==
|
||||
version "7.0.6"
|
||||
resolved "https://registry.yarnpkg.com/vite/-/vite-7.0.6.tgz#7866ccb176db4bbeec0adfb3f907f077881591d0"
|
||||
integrity sha512-MHFiOENNBd+Bd9uvc8GEsIzdkn1JxMmEeYX35tI3fv0sJBUTfW5tQsoaOwuY4KhBI09A3dUJ/DXf2yxPVPUceg==
|
||||
dependencies:
|
||||
esbuild "^0.25.0"
|
||||
fdir "^6.4.6"
|
||||
picomatch "^4.0.2"
|
||||
picomatch "^4.0.3"
|
||||
postcss "^8.5.6"
|
||||
rollup "^4.40.0"
|
||||
tinyglobby "^0.2.14"
|
||||
@@ -2901,24 +3078,29 @@ vscode-uri@^3.0.8:
|
||||
resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-3.1.0.tgz#dd09ec5a66a38b5c3fffc774015713496d14e09c"
|
||||
integrity sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==
|
||||
|
||||
vue-demi@latest:
|
||||
version "0.14.10"
|
||||
resolved "https://registry.yarnpkg.com/vue-demi/-/vue-demi-0.14.10.tgz#afc78de3d6f9e11bf78c55e8510ee12814522f04"
|
||||
integrity sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==
|
||||
|
||||
vue-tsc@^3.0.0:
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/vue-tsc/-/vue-tsc-3.0.3.tgz#5886b5030b4bbc832b039c36e3e259a620187a00"
|
||||
integrity sha512-uU1OMSzWE8/y0+kDTc0iEIu9v82bmFkGyJpAO/x3wQqBkkHkButKgtygREyOkxL4E/xtcf/ExvgNhhjdzonldw==
|
||||
version "3.0.4"
|
||||
resolved "https://registry.yarnpkg.com/vue-tsc/-/vue-tsc-3.0.4.tgz#f04f07a84046c923133ec588ef89ae1300e64e1a"
|
||||
integrity sha512-kZmSEjGtROApVBuaIcoprrXZsFNGon5ggkTJokmhQ/H1hMzCFRPQ0Ed8IHYFsmYJYvHBcdmEQVGVcRuxzPzNbw==
|
||||
dependencies:
|
||||
"@volar/typescript" "2.4.20"
|
||||
"@vue/language-core" "3.0.3"
|
||||
"@vue/language-core" "3.0.4"
|
||||
|
||||
vue@^3.5.13:
|
||||
version "3.5.17"
|
||||
resolved "https://registry.yarnpkg.com/vue/-/vue-3.5.17.tgz#ea8a6a45abb2b0620e7d479319ce8434b55650cf"
|
||||
integrity sha512-LbHV3xPN9BeljML+Xctq4lbz2lVHCR6DtbpTf5XIO6gugpXUN49j2QQPcMj086r9+AkJ0FfUT8xjulKKBkkr9g==
|
||||
version "3.5.18"
|
||||
resolved "https://registry.yarnpkg.com/vue/-/vue-3.5.18.tgz#3d622425ad1391a2b0138323211ec784f4415686"
|
||||
integrity sha512-7W4Y4ZbMiQ3SEo+m9lnoNpV9xG7QVMLa+/0RFwwiAVkeYoyGXqWE85jabU4pllJNUzqfLShJ5YLptewhCWUgNA==
|
||||
dependencies:
|
||||
"@vue/compiler-dom" "3.5.17"
|
||||
"@vue/compiler-sfc" "3.5.17"
|
||||
"@vue/runtime-dom" "3.5.17"
|
||||
"@vue/server-renderer" "3.5.17"
|
||||
"@vue/shared" "3.5.17"
|
||||
"@vue/compiler-dom" "3.5.18"
|
||||
"@vue/compiler-sfc" "3.5.18"
|
||||
"@vue/runtime-dom" "3.5.18"
|
||||
"@vue/server-renderer" "3.5.18"
|
||||
"@vue/shared" "3.5.18"
|
||||
|
||||
vuetify@^3.7.4:
|
||||
version "3.9.2"
|
||||
@@ -2977,6 +3159,11 @@ write-file-atomic@^6.0.0:
|
||||
imurmurhash "^0.1.4"
|
||||
signal-exit "^4.0.1"
|
||||
|
||||
ws@^8.5.0:
|
||||
version "8.18.3"
|
||||
resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.3.tgz#b56b88abffde62791c639170400c93dcb0c95472"
|
||||
integrity sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==
|
||||
|
||||
yallist@^3.0.2:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd"
|
||||
|
||||
Reference in New Issue
Block a user