diff --git a/README.md b/README.md index 16f54da7..7c1cfc40 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Bitbybit Monorepo -This git repo contains multiple bitbybit packages and contains code for core 3D algorithms of Bitbybit platform which are open-sourced under MIT license. +This git repo contains multiple bitbybit packages and code for core 3D algorithms of Bitbybit platform which are open-sourced under MIT license. # [FULL PLATFORM AT BITBYBIT.DEV](https://bitbybit.dev) # [LEARN BITBYBIT](https://learn.bitbybit.dev) diff --git a/docs/blog/2024-04-23-introducing-bitbybit-runner.md b/docs/blog/2024-04-23-introducing-bitbybit-runner.md index a137a945..dd293ac0 100644 --- a/docs/blog/2024-04-23-introducing-bitbybit-runner.md +++ b/docs/blog/2024-04-23-introducing-bitbybit-runner.md @@ -60,7 +60,7 @@ We've developed and launched three different types of examples to demonstrate a When you only need to run a script created in Bitbybit.dev without much external interaction, this is a good starting point. There are several ways to load the exported script file into your website, but perhaps the simplest is to just copy and paste its content and assign it to a variable or return it from a function. We've provided this example on three popular external coding sites: -* [StackBlitz Example](https://stackblitz.com/edit/stackblitz-starters-f6d3a2?file=script.js) +* [StackBlitz Example](https://stackblitz.com/edit/bitbybit-dev-runner-example-inline-string-embed-from-ret?file=script.js) * [JSFiddle Example](https://jsfiddle.net/matas_bitbybitdev/sa5jroqn/11/) * [CodePen Example](https://codepen.io/matas-bitbybit-dev/pen/XWQoxmX) @@ -98,7 +98,7 @@ While this example is basic, it includes all the essential elements of a 3D conf * Demonstration of how you can provide inputs to your exported Rete script and read outputs from it. Check out the examples: -* [StackBlitz Example](https://stackblitz.com/edit/stackblitz-starters-ohhh1g?file=script.js) +* [StackBlitz Example](https://stackblitz.com/edit/bitbybit-dev-runner-example-io-from-rete-editor?file=index.html,script.js) * [JSFiddle Example](https://jsfiddle.net/matas_bitbybitdev/z1pku4gj/3/) * [CodePen Example](https://codepen.io/matas-bitbybit-dev/pen/KKYbJdj) diff --git a/docs/docusaurus.config.ts b/docs/docusaurus.config.ts index 36a4613a..68beb1c9 100644 --- a/docs/docusaurus.config.ts +++ b/docs/docusaurus.config.ts @@ -30,7 +30,23 @@ const config: Config = { defaultLocale: "en", locales: ["en"], }, - + plugins: [ + [ + "@docusaurus/plugin-client-redirects", + { + redirects: [ + { + from: "/learn/npm-packages/start-with-three-js", + to: "/learn/npm-packages/threejs/start-with-three-js", + }, + { + from: "/learn/npm-packages/start-with-babylon-js", + to: "/learn/npm-packages/babylonjs/start-with-babylon-js", + }, + ], + } + ], + ], presets: [ [ "classic", @@ -65,7 +81,7 @@ const config: Config = { ], themeConfig: { // Replace with your project's social card - image: "img/docusaurus-social-card.jpg", + image: "img/learn-bitbybit-social-card.jpeg", colorMode: { defaultMode: "dark", disableSwitch: false, diff --git a/docs/learn/3d-bits/faq.md b/docs/learn/3d-bits/faq.md new file mode 100644 index 00000000..ced51980 --- /dev/null +++ b/docs/learn/3d-bits/faq.md @@ -0,0 +1,143 @@ +--- +sidebar_position: 2 +title: "3D Bits Shopify App - FAQ" +sidebar_label: "3D Bits FAQ" +description: "Frequently asked questions about using the 3D Bits app to integrate 3D models and product configurators into your Shopify store." +tags: [shopify, 3d-bits] +--- + +import Admonition from '@theme/Admonition'; + +# 3D Bits Shopify App: Frequently Asked Questions + +As 3D Bits makes its way into Shopify stores, we’ve started getting some recurring questions from merchants. So, here’s a quick FAQ with some honest answers to help you understand what 3D Bits can do for your store. + + +

If you have other questions or just need some initial guidance, please contact us, we're here to help you out!

+ info@bitbybit.dev +
+ +--- + +### Can I use 3D Bits if I have zero coding skills? + +**Yes, absolutely!** If you can click buttons and copy-paste, you’re good to go for basic 3D model display. + +**Here's the simple process:** +1. Install 3D Bits app, subscribe for a trial and pin it. +2. Go to Metafields sections within the app admin page and hit create button. +3. Upload your 3D models to Shopify via **Content > Files**. +4. Copy the link to your uploaded 3D model. +5. Paste this link into one of our designated 3D Bits metafields associated with your product. +6. Voilà! Your 3D model should now appear on your product page. + +Feeling a bit more adventurous but still don't want to code? You can try our **BITBYBIT VIEWER** editor block within the Shopify Theme Editor. It allows for arranging slightly fancier scenes with multiple models or different camera angles, still without writing any code – just courage required! + + + For a detailed walkthrough, check out our guide: 3D Bits Setup Guide. + + +--- + +### Can I build a product configurator without writing code? + +**To a certain extent, yes.** + +The **BITBYBIT VIEWER** block (used within the Viewer Editor) lets you match static 3D models with your existing Shopify product variants. This is great for handling common scenarios like: +* Showing a different 3D model for each color option (e.g., a blue chair model when "Blue" is selected). +* Displaying different models for size variations. + + + As technical founders, our initial inclination was to build in complex parametric logic for everything. However, we quickly realized that many merchants simply want to achieve straightforward visual changes based on standard Shopify variants – like showing the blue chair when "Blue" is selected. And that's perfectly fine and often all that's needed! 3D Bits handles this simple variant swapping effectively. + + +- Have GLTF files ready? Check this tutorial: [No-Code GLTF Configurators with BITBYBIT VIEWER Editor on Shopify](/learn/3d-bits/tutorials/viewer-no-code-gltf-configurators) +- Want to use 3D scans (Gaussian splatting)? [No-Code Gaussian Splat Configurators with BITBYBIT VIEWER Editor on Shopify](/learn/3d-bits/tutorials/viewer-no-code-3d-scan-configurators) + +For more complex configurators (e.g., where parts change dynamically beyond pre-set variants, or intricate rules are needed), you'd likely need to explore options involving some level of scripting, as discussed in later questions. + +--- + +### I already use [bitbybit.dev](https://bitbybit.dev) for my projects – can I connect those to Shopify? + +**Yes, you can!** + +* **For Simple Previews:** Use the **BITBYBIT PREVIEW** extension block in the Shopify Theme Editor. Make your project public on `bitbybit.dev`, and paste the project link into the block. That’s it! This is great for showcasing existing non-interactive or pre-animated scenes. +* **For More Interactivity:** If you want your `bitbybit.dev` script to react to Shopify variants or other page elements, you'll need to integrate your scripts using the **BITBYBIT RUNNER** theme extension block. This involves exporting your script from `bitbybit.dev` (as a JavaScript snippet) and then setting up the Runner block to execute it. This approach is more complex but offers much greater control. + + + Learn more about connecting your projects: Connecting bitbybit.dev Projects to Shopify. + + +--- + +### We’re developers building stores for merchants. Should we bother with 3D Bits? + +**Definitely.** + +While you *can* build everything from scratch (integrating a WebGL viewer, handling model loading, Shopify integration, etc.), ask yourself: do you really want to keep reinventing that wheel for each new theme or client? + + +3D Bits handles the essential groundwork: +* Easy 3D model embedding. +* Shopify metafield integration for 3D assets. +* Basic variant-to-model mapping. +* A bridge (the Runner block) for your custom JavaScript/TypeScript logic to interact with the 3D scene. + +This frees you up to focus on the unique business logic, creative 3D experiences, and advanced interactivity your clients need, rather than spending time wrangling 3D viewers into every theme variation. We’ve been there – it wasn't fun! 🥹 + + + We currently use BabylonJS in 3D Bits app. All of the videos and viewer editor is based on it. + + +--- + +### Can I use 3D Bits for complex pricing (e.g., a slider value changes the product price)? + +**Not directly for the pricing calculation itself.** + +3D Bits is focused on handling the **3D visualization**. It can: +* Read a value from a slider (or any other UI element on your page). +* Update the 3D model based on that value (e.g., change dimensions, swap parts). + +However, **3D Bits does not calculate or update the product price in Shopify.** Pricing logic, especially for complex, dynamically calculated prices, needs to be handled by: +* Shopify's built-in variant pricing. +* A dedicated third-party Shopify pricing app. +* Custom backend development with secure validation. + +Shopify offers three variant types with many options out of the box, which covers most standard pricing scenarios. For anything fancier, you’ll need to combine 3D Bits for the visuals with other tools or custom solutions for the pricing logic. + +--- + +### My product has a ton of configurable parts and complex logic. Can I build a fully custom configurator with 3D Bits? + +**Yes, if you or your team can write JavaScript or TypeScript.** + +This is where the **BITBYBIT RUNNER** theme extension block truly shines. It acts as a bridge: +1. You develop your complex configuration logic, part-swapping rules, and geometric manipulations as a script (e.g., using Rete, Blockly, or TypeScript on `bitbybit.dev` and then exporting it, or writing it directly for the runner). +2. The Runner block executes this script within your Shopify theme. +3. Your script can then interact with the 3D scene, listen to Shopify variant changes (or other custom UI elements you add to the page), and update the 3D model accordingly. + +3D Bits provides the 3D rendering pipeline and the connection to Shopify. You'll need to bring your own: +* Custom configuration logic (as a script). +* Pricing strategy (likely handled by Shopify or another app). +* Custom UI elements (if Shopify's default variant selectors aren't sufficient). + + + Dive deeper into building custom configurators: Using the Bitbybit Runner for Custom Logic. + + +--- + +### Does 3D Bits offer fancy UI controls for product pages (like custom sliders, color swatches, etc.)? + +**Nope. 3D Bits is not here to reinvent the dropdown or the color swatch.** + +There are many excellent Shopify apps and theme development techniques dedicated to creating sophisticated UI controls for product options. + +3D Bits focuses on the 3D visualization. It's designed to **listen** to what options are already selected on your product page (whether through standard Shopify variants or custom UI controls you've implemented) and then **update the 3D scene accordingly**: +* Show the correct 3D model or parts. +* Hide what shouldn’t be visible. +* Update 3D model dimensions or features based on selected options. + +**Think of 3D Bits as the 3D backbone of your product visualization – not the entire user interface nervous system. 💪** It plays well with others, allowing you to choose the best UI tools for your store while it handles the 3D heavy lifting. \ No newline at end of file diff --git a/docs/learn/3d-bits/theme-app-extensions/_category_.json b/docs/learn/3d-bits/theme-app-extensions/_category_.json index 1afc188a..38db85ae 100644 --- a/docs/learn/3d-bits/theme-app-extensions/_category_.json +++ b/docs/learn/3d-bits/theme-app-extensions/_category_.json @@ -1,4 +1,4 @@ { "label": "Theme App Extensions", - "position": 1 + "position": 3 } \ No newline at end of file diff --git a/docs/learn/3d-bits/tutorials/_category_.json b/docs/learn/3d-bits/tutorials/_category_.json index c57773eb..b9dada94 100644 --- a/docs/learn/3d-bits/tutorials/_category_.json +++ b/docs/learn/3d-bits/tutorials/_category_.json @@ -1,4 +1,4 @@ { "label": "Tutorials", - "position": 2 + "position": 4 } diff --git a/docs/learn/3d-bits/tutorials/viewer-no-code-gltf-configurators copy.md b/docs/learn/3d-bits/tutorials/viewer-no-code-gltf-configurators.md similarity index 100% rename from docs/learn/3d-bits/tutorials/viewer-no-code-gltf-configurators copy.md rename to docs/learn/3d-bits/tutorials/viewer-no-code-gltf-configurators.md diff --git a/docs/learn/intro.md b/docs/learn/intro.md index 9f757dc4..1f42679a 100644 --- a/docs/learn/intro.md +++ b/docs/learn/intro.md @@ -10,10 +10,36 @@ import Admonition from '@theme/Admonition'; # Welcome! 🎉 -We're thrilled you're interested in using our platform! These "Start" pages are designed to help you quickly get up to speed and begin creating amazing 3D experiences. +We're thrilled you're interested in using our platform! This site is designed to help you quickly get up to speed and begin creating amazing 3D experiences. + +In this essential introduction to Bitbybit video Matas Ubarevičius explains the fundamental ideas of the platform - if you haven't watched it yet - it's highly recommended. +
+ +
Let's find the best starting point for you: +### Are you a programmer? + +If you're a professional programmer, you can jump right into our [**TypeScript Monaco editor**](https://bitbybit.dev/app?editor=typescript). Find the [**API Docs here**](https://docs.bitbybit.dev). + +To get started: + +* We offer [**NPM packages**](/learn/npm-packages/intro) that you can incorporate into your own websites. + * *Note: These packages do not include our proprietary advanced algorithms or the models available in the 3D Models section.* +* Check out how to set up our algorithms with [**Three.JS**](/learn/npm-packages/threejs/intro) or [**Babylon.JS**](/learn/npm-packages/babylonjs/intro). We include some complete powerful demos with explanations. +* Also consider our course: [**Introduction To Programming 3D In TypeScript**](https://bitbybit.dev/school/courses/introduction-to-programming-3d-in-typescript). +* Or, if you're familiar with BabylonJS: [**Bitbybit For BabylonJS Developers**](https://bitbybit.dev/school/courses/bitbybit-for-babylonjs-developers). + These courses explore how our algorithms can create 3D CAD applications. + ### Are you looking for ready-made 3D models? Many of our standalone 3D model configurators require a subscription to our paid plans: Silver or Gold. @@ -65,15 +91,3 @@ This platform is a great place to teach 3D computational design, mathematics, ge If you're familiar with our tools and interested in becoming a teacher in our School to share your knowledge, please reach out to us at [info@bitbybit.dev](mailto:info@bitbybit.dev). - -### Are you a programmer? - -If you're a professional programmer, you can jump right into our **TypeScript Monaco editor**. - -To get started: - -* Consider our course: [**Introduction To Programming 3D In TypeScript**](https://bitbybit.dev/school/courses/introduction-to-programming-3d-in-typescript). -* Or, if you're familiar with BabylonJS: [**Bitbybit For BabylonJS Developers**](https://bitbybit.dev/school/courses/bitbybit-for-babylonjs-developers). - These courses explore how our algorithms can create 3D CAD applications. -* We also offer [**NPM packages**](/learn/npm-packages/intro) that you can incorporate into your own websites. - * *Note: These packages do not include our proprietary advanced algorithms or the models available in the 3D Models section.* \ No newline at end of file diff --git a/docs/learn/npm-packages/babylonjs/_category_.json b/docs/learn/npm-packages/babylonjs/_category_.json new file mode 100644 index 00000000..4154d49e --- /dev/null +++ b/docs/learn/npm-packages/babylonjs/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "BabylonJS", + "position": 3 +} diff --git a/docs/learn/npm-packages/babylonjs/advanced-parametric-3d-model.mdx b/docs/learn/npm-packages/babylonjs/advanced-parametric-3d-model.mdx new file mode 100644 index 00000000..f6c7c5c2 --- /dev/null +++ b/docs/learn/npm-packages/babylonjs/advanced-parametric-3d-model.mdx @@ -0,0 +1,403 @@ +--- +sidebar_position: 3 +title: "Advanced Parametric 3D Model with BabylonJS & Bitbybit" +sidebar_label: "Parametric Model (BabylonJS)" +description: "Learn how to build an advanced, interactive parametric 3D model using Bitbybit with BabylonJS, OCCT, and a GUI for real-time control." +tags: [npm-packages, babylonjs] +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import CodeBlock from '@theme/CodeBlock'; +import Admonition from '@theme/Admonition'; + +# Advanced Parametric 3D Model with BabylonJS & Bitbybit + +This tutorial explores building a sophisticated, interactive parametric 3D model utilizing Bitbybit's robust integration with the BabylonJS rendering engine. We will construct a configurable "Hex Shell" 3D shape, where its geometry is dynamically controlled by parameters from a `lil-gui` interface. The underlying complex CAD operations will be handled by the OpenCascade (OCCT) kernel, accessed via Bitbybit. + +You can see what the results of this app look like (rendered in Unreal Engine): +
+ +
+ +Through this example, you will learn to: + +* Set up a BabylonJS scene and rendering engine. +* Initialize Bitbybit with specific geometry kernels (OCCT in this case) for a BabylonJS environment. +* Create intricate parametric geometry using Bitbybit's OCCT API. +* Employ `lil-gui` to generate a user interface for real-time control over model parameters. +* Dynamically update the 3D model in the BabylonJS scene as UI parameters change. +* Implement a Level of Detail (LOD) strategy for efficient shape generation during interaction and finalization. +* Integrate functionality to export the 3D model in common formats like STEP, STL, and GLB. + +We are providing a higher level explanations of the codebase below, but for working reference always check this live example on StackBlitz, which, as platform evolves could change slightly. + +
+ +
+ +## Project Structure Overview + +A well-organized project structure is key for managing more complex applications. This example typically involves: + +* `index.html`: The entry point for the browser, hosting the canvas and loading our scripts. +* `style.css`: Contains basic CSS for page layout, canvas presentation, and UI elements such as a loading spinner. +* `src/main.ts`: The primary TypeScript file that orchestrates the entire application, from scene setup and Bitbybit initialization to GUI interactions and geometry updates. +* `src/models/`: A directory to define the data structures (TypeScript interfaces/types and initial values) for: + * `model.ts`: Parameters controlling the 3D shape's geometry. + * `kernel-options.ts`: Configuration for enabling Bitbybit geometry kernels. + * `current.ts`: References to current scene objects (meshes, lights, GUI instance). +* `src/helpers/`: This directory houses utility functions, each with a distinct responsibility: + * `init-babylonjs.ts`: Responsible for setting up the BabylonJS `Engine`, `Scene`, `Camera`, default lighting, and a ground plane. + * `init-kernels.ts`: Manages the initialization of the selected Bitbybit geometry kernels (e.g., OCCT). + * `create-shape.ts`: The core of the geometric logic, containing the functions that use Bitbybit's OCCT API to generate the parametric "Hex Shell" model. + * `create-gui.ts`: Configures the `lil-gui` panel, linking its controls to the parameters in `model.ts` and connecting them to the geometry update functions. + * `downloads.ts`: Implements the logic for exporting the generated 3D model to STEP, STL, and GLB file formats. + * `gui-helper.ts`: Provides simple utility functions for managing the GUI's visual state (e.g., showing/hiding a loading spinner, enabling/disabling GUI controls). +* `src/workers/`: This directory would contain the individual Web Worker files for each geometry kernel Bitbybit uses (e.g., `occt.worker.ts`). + + + For a detailed explanation on setting up the Web Worker files (e.g., `occt.worker.ts`), which are essential for running geometry kernels in a separate thread, please refer to our [**BabylonJS Integration Starter Tutorial**](./start-with-babylon-js) or a general guide on using workers with Bitbybit. This tutorial assumes that foundation is in place and focuses on the application logic. + + +## 1. HTML Setup (`index.html`) + +The `index.html` file provides the basic webpage structure. + + +{` + + + + + + Bitbybit & BabylonJS Hex Shell Example + + + + + + +`} + + +**Key elements:** +* A `` element: This is where BabylonJS will render the 3D scene. +* A ` + +`} + + +**Key elements:** +* A `` element where the Three.js scene will be rendered. +* A script tag to load our main application logic from `src/main.ts`. +* A simple Bitbybit logo link. + +## 2. Main Application Logic (`src/main.ts`) + +This is the heart of our application, orchestrating all the major components. + + +{`import './style.css'; +import { BitByBitBase, Inputs } from '@bitbybit-dev/threejs'; +import { model, type KernelOptions, current } from './models'; +import { + initKernels, + initThreeJS, + createGui, + createShapeLod1, + createShapeLod2, + createDirLightsAndGround, + disableGUI, + enableGUI, + hideSpinner, + showSpinner, + downloadGLB, + downloadSTL, + downloadStep, +} from './helpers'; + +// Configure which geometry kernels to enable +const kernelOptions: KernelOptions = { + enableOCCT: true, // We'll use OCCT for this parametric model + enableJSCAD: false, + enableManifold: false, +}; + +// Start the application +start(); + +async function start() { + // 1. Initialize the Three.js scene, camera, renderer, and basic lights/ground + const { scene } = initThreeJS(); + createDirLightsAndGround(scene, current); // 'current' stores references to scene objects + + // 2. Initialize Bitbybit with the Three.js scene and selected kernels + const bitbybit = new BitByBitBase(); + await initKernels(scene, bitbybit, kernelOptions); + + // Variables to hold the OCCT shape representation and shapes to clean up + let finalShape: Inputs.OCCT.TopoDSShapePointer | undefined; + let shapesToClean: Inputs.OCCT.TopoDSShapePointer[] = []; // Important for memory management + + // 3. Connect download functions to the model object (used by GUI) + model.downloadStep = () => downloadStep(bitbybit, finalShape); + model.downloadGLB = () => downloadGLB(scene); + model.downloadSTL = () => downloadSTL(scene); + + // 4. Create the GUI panel and link it to model parameters and the updateShape function + createGui(current, model, updateShape); + + // 5. Basic animation setup for rotating the model + const rotationSpeed = 0.0005; + const rotateGroup = () => { + if ( + model.rotationEnabled && + current.group1 && // Assumes group1, group2, dimensions are populated by createShape... + current.group2 && + current.dimensions + ) { + current.group1.rotation.y -= rotationSpeed; + current.group2.rotation.y -= rotationSpeed; + current.dimensions.rotation.y -= rotationSpeed; + } + }; + + // Hook into Three.js render loop for animation + scene.onBeforeRender = () => { + rotateGroup(); + }; + + // 6. Initial shape creation (Level of Detail 1 - faster preview) + finalShape = await createShapeLod1( + bitbybit, + scene, + model, // Current model parameters + shapesToClean, // Array to track OCCT shapes for later cleanup + current // Object to store references to current Three.js groups + ); + + // 7. Function to update the shape when GUI parameters change + async function updateShape(finish: boolean) { + disableGUI(); // Prevent further interaction during update + showSpinner(); // Indicate processing + + // Remove previous Three.js groups from the scene + current.group1?.traverse((obj) => scene?.remove(obj)); + current.group2?.traverse((obj) => scene?.remove(obj)); + current.dimensions?.traverse((obj) => scene?.remove(obj)); + // Note: OCCT shapes are cleaned up within createShapeLod1/2 via shapesToClean + + if (finish) { // 'finish' is true when "Finalize" button in GUI is clicked + finalShape = await createShapeLod2( // Higher detail + bitbybit, scene, model, shapesToClean, current + ); + } else { // Default update (e.g., from slider drag) + finalShape = await createShapeLod1( // Lower detail for speed + bitbybit, scene, model, shapesToClean, current + ); + } + + hideSpinner(); + enableGUI(); // Re-enable GUI + } +} +`} + + +**Explanation of `main.ts`:** + +1. **Imports:** Pulls in necessary Bitbybit modules, data models, and helper functions. +2. **`kernelOptions`:** Configures which Bitbybit geometry kernels (OCCT, JSCAD, Manifold) will be initialized. For this example, only OCCT is enabled as it's used for the parametric modeling. +3. **`start()` function:** The main asynchronous function that orchestrates the application. + * **`initThreeJS()` & `createDirLightsAndGround()`:** Sets up the basic Three.js environment. + * **`BitByBitBase` & `initKernels()`:** Initializes the Bitbybit library, linking it to the Three.js scene and loading the configured OCCT kernel worker. + * **`finalShape` & `shapesToClean`:** `finalShape` will hold a reference to the main OCCT geometry. `shapesToClean` is crucial for managing memory in OCCT by keeping track of intermediate shapes that need to be explicitly deleted after they are no + longer needed. + * **Download Functions:** Attaches download helper functions to the `model` object. These will be triggered by buttons in the GUI. + * **`createGui()`:** Initializes the `lil-gui` panel, connecting its controls to the properties defined in `model.ts` and providing the `updateShape` function as a callback when parameters change. + * **Rotation Logic:** Sets up a simple animation to rotate the generated 3D groups if `model.rotationEnabled` is true. + * **Initial Shape Creation:** Calls `createShapeLod1` to generate and draw the initial 3D model with a lower level of detail for faster startup. + * **`updateShape(finish: boolean)` function:** + * This function is called by the GUI when a parameter changes. + * It disables the GUI and shows a spinner to indicate processing. + * It removes the previously rendered Three.js `Group` objects (`current.group1`, `current.group2`, `current.dimensions`) from the scene. + * Crucially, the `createShapeLod1` and `createShapeLod2` functions are responsible for cleaning up OCCT shapes using the `shapesToClean` array. + * It then calls either `createShapeLod1` (for quick updates, e.g., during slider dragging) or `createShapeLod2` (for a more detailed final version when a "Finalize" button is clicked). + * Finally, it hides the spinner and re-enables the GUI. + +## 3. Helper Functions (`src/helpers/`) + +The `helpers` directory modularizes different aspects of the application. + +### `init-threejs.ts` & `init-kernels.ts` + +* **`initThreeJS()`:** Contains standard Three.js setup for scene, camera, WebGL renderer, basic lighting (HemisphereLight, DirectionalLights), a ground plane, and OrbitControls for camera manipulation. It also sets up the animation loop. +* **`createDirLightsAndGround()`:** A helper to specifically add directional lights (for shadows) and a ground plane to the scene. +* **`initKernels()`:** This function is responsible for: + 1. Conditionally creating Web Worker instances for each kernel specified in `kernelOptions`. + 2. Calling `bitbybit.init(...)` to link Bitbybit with the Three.js scene and these worker instances. + 3. Asynchronously waiting for each selected and available kernel to report that it has been fully initialized before resolving. This ensures kernels are ready before use. + + +{`// ... imports ... +export async function initKernels( + scene: Scene, + bitbybit: BitByBitBase, + options: KernelOptions +): Promise<{ message: string }> { + // 1. Conditionally create worker instances based on options + // (e.g., new Worker(new URL('../workers/occt.worker.ts', import.meta.url), ...)) + // 2. Initialize Bitbybit with scene and worker instances + // await bitbybit.init(scene, occtWorker, jscadWorker, manifoldWorker); + // 3. Collect and await promises for kernel initializations + // (e.g., using firstValueFrom on bitbybit.occtWorkerManager.occWorkerState$) + // 4. Resolve once selected kernels are ready + return { message: "Kernels initialized" }; +}`} + + +### `create-shape.ts` (Core Geometry Logic) + +This is the most complex file, containing the specific OCCT operations to generate the parametric shape. It typically includes: + +* Functions like `createShapeLod1` (Level of Detail 1 - faster, less detailed) and `createShapeLod2` (Level of Detail 2 - slower, more detailed). +* **Memory Management:** Before creating new OCCT geometry, it calls `bitbybit.occt.deleteShapes({ shapes: shapesToClean })` to free memory used by previous intermediate OCCT shapes. New intermediate shapes created are added to `shapesToClean`. +* **Geometric Operations:** Uses various functions from `bitbybit.occt.shapes`, `bitbybit.occt.operations`, `bitbybit.occt.transforms`, etc., to: + * Create primitive wires (e.g., ellipses using `wire.createEllipseWire`). + * Transform these wires (rotate, translate). + * Loft surfaces between wires (`operations.loft`). + * Offset faces (`operations.offset`). + * Subdivide faces into patterns (e.g., `face.subdivideToHexagonWires`). + * Create solids from these operations. + * Create compound shapes. +* **Dimensioning (Optional):** The example includes logic to create OCCT dimension entities (`dimensions.simpleLinearLengthDimension`, `dimensions.simpleAngularDimension`) which are then also drawn. +* **Drawing:** + * It uses `bitbybit.draw.drawAnyAsync({ entity: occtShape, options: drawOptions })` to convert the final OCCT shapes into Three.js meshes and add them to the scene. + * It often creates separate Three.js `Group` objects for different parts of the model (e.g., `current.group1`, `current.group2`) for easier management and independent animation. + * Materials (`MeshPhongMaterial`) are created and applied. + + + The specific OCCT functions used (like `loft`, `offset`, `subdivideToHexagonWires`, `makeCompound`) are powerful CAD operations. Understanding their parameters and behavior is key to creating complex parametric models with OCCT. Refer to the Bitbybit API documentation for details on each. + + +### `create-gui.ts` + +This file uses the `lil-gui` library to create a user interface panel. + + +{`import GUI from 'lil-gui'; +// ... other imports ... +export const createGui = ( + current: Current, + model: Model, + updateShape: (finish: boolean) => void +) => { + model.update = () => updateShape(true); // Link "Finalize" button to LOD2 update + const gui = new GUI(); + current.gui = gui; // Store reference to GUI + + // Add controls for each parameter in the 'model' object + gui.add(model, 'uHex', 1, 14, 1).name('Hexagons U').onFinishChange(() => updateShape(false)); + // ... more gui.add() calls for vHex, height, colors, etc. ... + // .onFinishChange(() => updateShape(false)) calls LOD1 update for sliders + // .onChange(...) for color pickers to update material colors directly + + gui.add(model, 'update').name('Finalize'); // Button to trigger LOD2 update + gui.add(model, 'downloadSTL').name('Download STL'); + // ... download buttons ... +};`} + + +* It creates a new `GUI` instance. +* For each parameter in the `model` object (defined in `models/model.ts`), it adds a corresponding control (slider, color picker, checkbox). +* `onFinishChange` (for sliders) or `onChange` (for continuous updates like color pickers) callbacks are used to: + * Update the `model` object with the new parameter value. + * Call the `updateShape(false)` function (from `main.ts`) to regenerate the geometry with LOD1 (quick preview). +* A "Finalize" button calls `updateShape(true)` to generate the high-detail LOD2 version. +* Buttons are added to trigger the download functions. + +### `downloads.ts` + +Contains functions to export the generated 3D model: +* `downloadStep()`: Uses `bitbybit.occt.io.saveShapeSTEP()` to save the `finalShape` (the OCCT compound) as a STEP file. It includes a mirroring transformation, which might be necessary due to coordinate system differences. +* `downloadSTL()`: Uses `THREE.STLExporter` to export the entire Three.js scene as an STL file. +* `downloadGLB()`: Uses `THREE.GLTFExporter` to export the Three.js scene as a GLB (binary GLTF) file. + +### `gui-helper.ts` + +Simple utility functions to manage the UI during processing: +* `disableGUI()` / `enableGUI()`: Make the `lil-gui` panel non-interactive and visually dimmed during updates. +* `showSpinner()` / `hideSpinner()`: Display or hide a simple CSS-based loading spinner overlay. + +## 4. Data Models (`src/models/`) + +* **`current.ts`:** Defines a `Current` type and an instance to hold references to currently active Three.js objects (like `Group`s for different model parts, lights, ground) and the `lil-gui` instance. This helps in easily accessing and manipulating these objects from different parts of the code. +* **`kernel-options.ts`:** Defines the `KernelOptions` interface used in `main.ts` to specify which geometry kernels (OCCT, JSCAD, Manifold) should be initialized by Bitbybit. +* **`model.ts`:** Defines the `Model` type and a default `model` object. This object holds all the parameters that control the geometry of the 3D shape (e.g., `uHex`, `vHex`, `height`, colors, precision). The `lil-gui` directly manipulates this object. It also includes optional function signatures for `update` and download methods, which are later assigned in `main.ts` and `create-gui.ts`. + +## 5. Styles (`style.css`) + +The `style.css` file provides basic styling: +* Resets body margin and sets a background color. +* Styles for the Bitbybit logo link. +* CSS for the `lds-ellipsis` loading spinner animation. + +## Conclusion + +This advanced example showcases a more complete workflow for creating parametric and interactive 3D applications with Bitbybit and Three.js. Key takeaways include: + +* **Modular Code Structure:** Separating concerns into helper functions and data models makes the project more manageable. +* **Parametric Control:** Using a data model (`model.ts`) and a GUI (`lil-gui`) to drive geometry changes. +* **Level of Detail (LOD):** Implementing different detail levels for shape generation (`createShapeLod1` vs. `createShapeLod2`) can significantly improve performance during interactive adjustments. +* **OCCT Memory Management:** The practice of tracking and deleting intermediate OCCT shapes (`shapesToClean`) is crucial for preventing memory leaks in complex CAD operations. +* **Kernel Initialization:** Selectively initializing only the necessary geometry kernels. +* **Export Functionality:** Integrating common 3D file export options. + +By understanding these components and their interactions, you can build sophisticated and highly configurable 3D experiences on the web. \ No newline at end of file diff --git a/docs/learn/npm-packages/threejs/intro.md b/docs/learn/npm-packages/threejs/intro.md new file mode 100644 index 00000000..92558d1d --- /dev/null +++ b/docs/learn/npm-packages/threejs/intro.md @@ -0,0 +1,89 @@ +--- +sidebar_position: 1 +title: "Introduction to Three.js" +sidebar_label: "Three.js Overview" +description: "An overview of Three.js, a powerful JavaScript library for creating and displaying 3D graphics in web browsers, and how it's integrated with Bitbybit." +tags: [npm-packages, threejs] +--- + +import Admonition from '@theme/Admonition'; + +# Introduction to Three.js: Powering 3D on the Web + +Three.js is a cross-browser JavaScript library used to create and display animated 3D computer graphics in a web browser using WebGL. If you're looking to bring interactive 3D experiences to your web projects, Three.js is one of the most popular and powerful tools available. + +**Visit the official Three.js homepage:** threejs.org + +Three.js Logo + + +## What is Three.js Capable Of? + +At its core, Three.js provides a high-level abstraction over WebGL (Web Graphics Library), which is a low-level JavaScript API for rendering 2D and 3D graphics within any compatible web browser without the use of plug-ins. This abstraction makes it significantly easier to work with 3D graphics on the web. + +Key capabilities and features include: + +* **Scene Management:** Organizes all 3D objects, lights, and cameras into a hierarchical scene graph, making it easy to manage complex environments. +* **Cameras:** Offers various camera types (Perspective, Orthographic) to control how the scene is viewed. +* **Geometry:** Provides a wide range of built-in primitive geometries (cubes, spheres, planes, cylinders, tori, etc.) and supports loading custom geometries from various 3D file formats (like GLTF, OBJ, FBX). +* **Materials & Textures:** A rich material system allows for defining the appearance of objects, including support for physically-based rendering (PBR) materials, textures, bump maps, normal maps, environment maps, and more. +* **Lights & Shadows:** Supports different types of lights (Ambient, Directional, Point, Spot, Hemisphere) and various shadow mapping techniques to create realistic lighting and shadows. +* **Animation:** Includes systems for animating objects, skeletons (for character animation), and morph targets. +* **Loaders:** A comprehensive set of loaders for importing 3D models, textures, and other assets from popular 3D software. +* **Raycasting:** Allows for picking objects in the scene by casting rays (e.g., to detect mouse clicks on 3D objects). +* **Shaders:** Supports custom GLSL shaders for advanced visual effects and rendering techniques. +* **Post-processing:** A framework for applying full-screen visual effects to the rendered scene (e.g., bloom, depth of field, SSAO). +* **Renderers:** Primarily uses a WebGL renderer, but also has experimental support for other renderers like WebGPU (via compute Piplelines) and CSS3DRenderer. +* **Extensibility:** Designed to be modular, allowing developers to easily extend its functionality. + +## Why is Three.js So Popular? + +Three.js has gained immense popularity for several reasons: + +* **Accessibility:** It significantly lowers the barrier to entry for WebGL development. +* **Large and Active Community:** A vast and vibrant community means: + * Abundant tutorials, articles, and examples. + * Quick help and support through forums and Q&A sites. + * A wealth of open-source projects built with Three.js. +* **Extensive Ecosystem:** Numerous third-party libraries, tools, and extensions are available to augment Three.js capabilities (e.g., physics engines, UI libraries, advanced controls). +* **Flexibility:** It's a library, not a restrictive framework, giving developers a lot of control over their application structure. +* **Performance:** While WebGL itself can be complex to optimize, Three.js provides many tools and best practices to achieve good performance. + +## Learning Resources & Community + +If you're interested in diving deeper into Three.js, here are some valuable resources: + +* **Official Documentation:** Three.js Documentation - The primary source for API references and guides. +* **Official Examples:** Three.js Examples - A huge collection of live examples showcasing various features. +* **Three.js Journey:** Three.js Journey - A highly recommended, comprehensive course by Bruno Simon. +* **Discover Three.js:** Discover Three.js (Book) - A detailed online book. +* **Three.js Forum (Official):** discourse.threejs.org - The best place to ask questions and engage with the community. +* **Stack Overflow:** Many Three.js questions are asked and answered on Stack Overflow (tagged 'three.js'). +* **GitHub Repository:** mrdoob/three.js - Explore the source code and contribute. + +## How Bitbybit Uses Three.js + +Bitbybit's core architecture is designed to be game engine agnostic, meaning its fundamental geometry processing and CAD algorithms are independent of any specific rendering engine. However, to display 3D content in a web browser, a rendering engine is essential. + +Three.js is one of the rendering engines for which Bitbybit provides an official integration layer. + +* **Integration Package:** We offer the `@bitbybit-dev/threejs` NPM package. This package acts as a bridge, taking the geometric data generated by Bitbybit's core (which might originate from OCCT, JSCAD, or other kernels) and translating it into Three.js specific objects like `THREE.Group`, `THREE.Mesh`, `THREE.BufferGeometry`, and `THREE.Material`. +* **Drawing Logic:** Functions within this package, notably `drawAnyAsync`, are responsible for efficiently creating and rendering these Three.js objects within your Three.js scene. + + + ThreeJS support is only offered via our npm package. Due to historical reasons for our visual programming editors we use BabylonJS game engine - another great open-source WebGL engine. + + +By using `@bitbybit-dev/threejs`, developers can leverage Bitbybit's powerful CAD and computational geometry features while working within the familiar and extensive Three.js ecosystem. + +**Source Code for Bitbybit's Three.js Integration:** +You can find the source code for our Three.js integration package in our main GitHub repository, typically within a path like: +bitbybit-dev/bitbybit/tree/master/packages/dev/threejs + +--- + +Whether you're building complex CAD tools, interactive product configurators, data visualizations, or artistic 3D experiences, understanding Three.js can significantly enhance your capabilities as a web developer. Bitbybit's integration aims to make it easier to combine powerful geometry generation with this versatile rendering library. \ No newline at end of file diff --git a/docs/learn/npm-packages/start-with-three-js.md b/docs/learn/npm-packages/threejs/start-with-three-js.md similarity index 86% rename from docs/learn/npm-packages/start-with-three-js.md rename to docs/learn/npm-packages/threejs/start-with-three-js.md index 295eb289..64d4aaaa 100644 --- a/docs/learn/npm-packages/start-with-three-js.md +++ b/docs/learn/npm-packages/threejs/start-with-three-js.md @@ -1,7 +1,7 @@ --- sidebar_position: 2 title: Using Bitbybit with Three.js -sidebar_label: Three.js Integration +sidebar_label: Three.js Starter Template description: Learn how to set up and use the @bitbybit-dev/threejs package with Vite to create 3D CAD applications, and control which geometry kernels (OCCT, JSCAD, Manifold) are initialized. tags: [npm-packages, threejs, occt, manifold, jscad] --- @@ -206,7 +206,7 @@ import { Vector3, WebGLRenderer, } from 'three'; -import { first } from 'rxjs'; +import { first, firstValueFrom, tap } from 'rxjs'; // Define an interface for kernel options interface KernelOptions { @@ -294,91 +294,121 @@ function initThreeJS() { // --- 5. Bitbybit Kernel Initialization Logic --- async function initWithKernels( - scene: Scene, - bitbybit: BitByBitBase, - options: KernelOptions -): Promise<{ message: string }> { // Added explicit return type for clarity - return new Promise(async (resolve) => { + scene: Scene, + bitbybit: BitByBitBase, + options: KernelOptions +): Promise<{ message: string }> { let occtWorkerInstance: Worker | undefined; let jscadWorkerInstance: Worker | undefined; let manifoldWorkerInstance: Worker | undefined; - // Conditionally create worker instances based on options + // 1. Conditionally create worker instances if (options.enableOCCT) { - occtWorkerInstance = new Worker( + occtWorkerInstance = new Worker( new URL('./workers/occt.worker.ts', import.meta.url), { name: 'OCC_WORKER', type: 'module' } - ); + ); } if (options.enableJSCAD) { - jscadWorkerInstance = new Worker( + jscadWorkerInstance = new Worker( new URL('./workers/jscad.worker.ts', import.meta.url), { name: 'JSCAD_WORKER', type: 'module' } - ); + ); } if (options.enableManifold) { - manifoldWorkerInstance = new Worker( + manifoldWorkerInstance = new Worker( new URL('./workers/manifold.worker.ts', import.meta.url), { name: 'MANIFOLD_WORKER', type: 'module' } - ); + ); } - // Initialize Bitbybit with the (potentially undefined) worker instances + // 2. Initialize Bitbybit await bitbybit.init( - scene, - occtWorkerInstance, - jscadWorkerInstance, - manifoldWorkerInstance + scene, + occtWorkerInstance, + jscadWorkerInstance, + manifoldWorkerInstance ); - // Logic to wait for selected kernels to be initialized - let nrResolved = 0; - let resolutionsNeeded = 0; + // 3. Collect promises for kernel initializations + const initializationPromises: Promise[] = []; + let anyKernelSelectedForInit = false; - const checkIfAllInitialized = () => { - if (nrResolved === resolutionsNeeded) { - console.log('Selected kernels initialized:', options); - resolve({ message: 'Selected kernels initialized successfully.' }); - } - }; + if (options.enableOCCT) { + anyKernelSelectedForInit = true; + if (bitbybit.occtWorkerManager) { + initializationPromises.push( + firstValueFrom( + bitbybit.occtWorkerManager.occWorkerState$.pipe( + first((s) => s.state === OccStateEnum.initialised), + tap(() => console.log('OCCT Initialized')) + ) + ).then(() => {}) // Ensure the promise resolves to void for Promise.all + ); + } else { + console.warn( + 'OCCT enabled in options, but occtWorkerManager not found after init.' + ); + } + } - if (options.enableOCCT && bitbybit.occtWorkerManager) { - resolutionsNeeded++; - bitbybit.occtWorkerManager.occWorkerState$ - .pipe(first((s) => s.state === OccStateEnum.initialised)) - .subscribe(() => { - console.log('OCCT Initialized'); - nrResolved++; - checkIfAllInitialized(); - }); + if (options.enableJSCAD) { + anyKernelSelectedForInit = true; + if (bitbybit.jscadWorkerManager) { + initializationPromises.push( + firstValueFrom( + bitbybit.jscadWorkerManager.jscadWorkerState$.pipe( + first((s) => s.state === JscadStateEnum.initialised), + tap(() => console.log('JSCAD Initialized')) + ) + ).then(() => {}) + ); + } else { + console.warn( + 'JSCAD enabled in options, but jscadWorkerManager not found after init.' + ); + } } - if (options.enableJSCAD && bitbybit.jscadWorkerManager) { - resolutionsNeeded++; - bitbybit.jscadWorkerManager.jscadWorkerState$ - .pipe(first((s) => s.state === JscadStateEnum.initialised)) - .subscribe(() => { - console.log('JSCAD Initialized'); - nrResolved++; - checkIfAllInitialized(); - }); + + if (options.enableManifold) { + anyKernelSelectedForInit = true; + if (bitbybit.manifoldWorkerManager) { + initializationPromises.push( + firstValueFrom( + bitbybit.manifoldWorkerManager.manifoldWorkerState$.pipe( + first((s) => s.state === ManifoldStateEnum.initialised), + tap(() => console.log('Manifold Initialized')) + ) + ).then(() => {}) + ); + } else { + console.warn( + 'Manifold enabled in options, but manifoldWorkerManager not found after init.' + ); + } } - if (options.enableManifold && bitbybit.manifoldWorkerManager) { - resolutionsNeeded++; - bitbybit.manifoldWorkerManager.manifoldWorkerState$ - .pipe(first((s) => s.state === ManifoldStateEnum.initialised)) - .subscribe(() => { - console.log('Manifold Initialized'); - nrResolved++; - checkIfAllInitialized(); - }); + + // 4. Wait for selected & available kernels or handle no selection/availability + if (!anyKernelSelectedForInit) { + console.log('No kernels selected for initialization.'); + return { message: 'No kernels selected for initialization.' }; } - // If no kernels were selected to be enabled - if (resolutionsNeeded === 0) { - console.log('No kernels selected for initialization.'); - resolve({ message: 'No kernels selected for initialization.' }); + if (initializationPromises.length === 0) { + // Kernels were selected, but none were awaitable (e.g., managers missing for all selected) + console.log( + 'Kernels were selected, but none had managers available for awaiting initialization.' + ); + return { + message: 'Selected kernels were not awaitable for initialization state.', + }; } - }); + + await Promise.all(initializationPromises); + console.log('Selected and awaitable kernels initialized:', options); + return { + message: 'Selected and awaitable kernels initialized successfully.', + }; } // --- 6. Geometry Creation Functions (Examples) --- diff --git a/docs/learn/runners/intro-blockly.mdx b/docs/learn/runners/intro-blockly.mdx index 939790f4..7c89ff6c 100644 --- a/docs/learn/runners/intro-blockly.mdx +++ b/docs/learn/runners/intro-blockly.mdx @@ -1,5 +1,5 @@ --- -sidebar_position: 3 +sidebar_position: 4 title: Introduction to Bitbybit Runner with Blockly sidebar_label: Runner with Blockly description: Learn how to create a 3D website using Bitbybit Runner by integrating a visual program built with the Blockly editor into a StackBlitz project. diff --git a/docs/learn/runners/intro-rete.mdx b/docs/learn/runners/intro-rete.mdx index 5a2beaf2..71cd2259 100644 --- a/docs/learn/runners/intro-rete.mdx +++ b/docs/learn/runners/intro-rete.mdx @@ -1,5 +1,5 @@ --- -sidebar_position: 2 +sidebar_position: 3 title: Introduction to Bitbybit Runner - Your First 3D Website sidebar_label: Runner with Rete description: Learn how to create a simple 3D website using Bitbybit Runner & Rete editor, controlling a 3D cube's size with a UI input on StackBlitz. diff --git a/docs/learn/runners/intro-typescript.mdx b/docs/learn/runners/intro-typescript.mdx index 2db2b5d6..0bdfa758 100644 --- a/docs/learn/runners/intro-typescript.mdx +++ b/docs/learn/runners/intro-typescript.mdx @@ -1,5 +1,5 @@ --- -sidebar_position: 4 +sidebar_position: 5 title: Introduction to Bitbybit Runner with TypeScript sidebar_label: Runner with TypeScript description: Learn how to create a 3D website using Bitbybit Runner by integrating a TypeScript program built with Bitbybit into a StackBlitz project. diff --git a/docs/learn/runners/live-examples/_category_.json b/docs/learn/runners/live-examples/_category_.json new file mode 100644 index 00000000..71a11a20 --- /dev/null +++ b/docs/learn/runners/live-examples/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "Live Examples", + "position": 2 +} diff --git a/docs/learn/runners/live-examples/configurable-cad-part.mdx b/docs/learn/runners/live-examples/configurable-cad-part.mdx new file mode 100644 index 00000000..3ca520b7 --- /dev/null +++ b/docs/learn/runners/live-examples/configurable-cad-part.mdx @@ -0,0 +1,398 @@ +--- +sidebar_position: 2 +title: "Interactive 3D Models with Runner & Inputs" +sidebar_label: "Rete Script with Inputs" +description: "Learn how to create interactive 3D models on your website by passing inputs to Rete visual programs executed with the Bitbybit Runner." +tags: [runners, rete] +--- + +import BitByBitRenderCanvas from '@site/src/components/BitByBitRenderCanvas'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import CodeBlock from '@theme/CodeBlock'; +import Admonition from '@theme/Admonition'; + +# Interactive 3D Models with Runner & Inputs + +In the previous tutorial, we learned how to run a static Rete script on a webpage using the Bitbybit Runner. Now, let's take it a step further and explore how to make your embedded 3D content interactive by: + +1. **Passing inputs from your webpage to the Rete script.** +2. **Receiving outputs (like created meshes) back from the script.** +3. **Updating the 3D scene dynamically by re-executing the script with new inputs and disposing of old geometry.** + +This allows you to build powerful 3D product configurators, interactive data visualizations, or any application where users can modify parameters and see the 3D model update in real time. + +## The Rete Script: A Parametric Industrial Part + +For this tutorial, we'll use a Rete script that generates a parametric industrial-style 3D part. This script is designed to accept inputs such as `radius1`, `radius2`, and `distance`, which will control its geometry. + +Below is an interactive preview of the Rete visual program. Notice how this script might have specific "Input" nodes designed to receive data from the runner. + + + +## Exporting the Script and Designing for Inputs/Outputs + +When you design a Rete script intended for use with the runner and external inputs/outputs: + +* **Input Nodes:** Use specific "Input" nodes within your Rete graph (e.g., "Runner Number Input," "Runner Vector Input"). These nodes will receive values passed via the `inputs` object in `runner.executeScript(exportedScript(), inputs)`. +* **Output Nodes:** Similarly, use "Output" nodes (e.g., "Runner Geometry Output") to define what data or geometry the script should return. The `runner.executeScript()` method returns a promise that resolves with these outputs. + +The Bitbybit "Export to Runner" feature will generate a JavaScript function string that accommodates these input and output mechanisms. + +## Live Demo: Interactive Control + +Before diving into the code, let's see the final result in action with a live StackBlitz demo. This environment simulates how you can integrate HTML controls (buttons, sliders, etc.) to modify parameters and dynamically update the 3D model rendered by the Bitbybit Runner. + +**Why is this interactive demo important?** + +* **Dynamic Interaction:** It showcases the core concept of this tutorial – modifying a 3D model in real-time based on user input from the webpage. +* **Input/Output Flow:** You can observe how changes made via HTML controls are passed to the Rete script, and how the script's output (the 3D meshes) is used to update the scene. +* **Practical Use Case:** This example is a simplified version of what you might build for a product configurator or an interactive educational tool. + +
+ +
+ +## Setting up Your HTML Page with Controls + +The HTML structure will be similar to the previous tutorial but will now include UI elements (buttons and spans) to control the Rete script's parameters. + + +{` + + + Runner Example - IO from Rete editor + + + + {/* Ensure version is current */} + + + +
+ +

Runner Example - Interactive Rete Script

+
+ +
+ + {/* Controls for script parameters */} +
+
+ + Radius1 is 4 + +
+
+ + Radius2 is 2 + +
+
+ + Distance is 24 + +
+
+ + +
+ +`} +
+ +**Key additions to `index.html`:** +* **Control Elements:** We've added `div`s containing `button` elements (for incrementing/decrementing values) and `span` elements (to display the current parameter values). +* **`onclick` Attributes:** The buttons call a JavaScript function `updateProp()` (which we'll define in `script.js`) to modify the input parameters. + +## Implementing the Interactive Logic (`script.js`) + +The `script.js` file now becomes more involved as it needs to handle initial values, update these values based on user interaction, re-execute the Rete script, and manage the previously created 3D objects. + + +{`// Initial input values for the Rete script +window.inputs = { + radius1: 4, + radius2: 2, + distance: 24, +}; + +// Bounds for the input values to keep them within a reasonable range +const bounds = { + radius1Min: 2, radius1Max: 10, + radius2Min: 2, radius2Max: 10, + distanceMin: 5, distanceMax: 40, +}; + +// Store previously created meshes to dispose of them before re-rendering +window.previousMeshes = []; +updateLabels(); // Initialize labels on the page + +const runner = window.bitbybitRunner.getRunnerInstance(); + +const runnerOptions = { + canvasId: 'myCanvas', + canvasZoneClass: 'myCanvasZone', + enablePhysics: false, // Assuming no physics for this example + enableOCCT: true, // Script uses OCCT + enableJSCAD: false, + enableManifold: false, + enableKeyEventListeners: false, + loadFonts: ['Roboto'], // If your script uses specific fonts for 3D text +}; + +// Initialize the runner and get access to bitbybit API and Bit (Inputs) objects +const { bitbybit, Bit } = await runner.run(runnerOptions); + +// Optional: Adjust camera after runner initialization if needed +// This prevents the Rete script from resetting the camera on each execution if it also has camera controls. +const cameraOpt = new Bit.Inputs.BabylonScene.CameraConfigurationDto(); +cameraOpt.position = [-30, 25, -35]; // Adjusted for better view of the industrial part +cameraOpt.lookAt = [0, 0, 0]; +bitbybit.babylon.scene.adjustActiveArcRotateCamera(cameraOpt); + +// Initial execution of the Rete script +let scriptResult = await runner.executeScript(exportedScript(), inputs); +previousMeshes = scriptResult.meshes || []; // Store the output meshes + +// Function to update a property, re-run the script, and update the scene +async function updateProp(propName, increase) { + let currentValue = inputs[propName]; + if (increase) { + currentValue++; + } else { + currentValue--; + } + + // Check against bounds + if (currentValue >= bounds[propName + 'Min'] && currentValue <= bounds[propName + 'Max']) { + buttonActivation(true); // Disable buttons during processing + + inputs[propName] = currentValue; + updateLabels(); // Update the displayed value on the page + + // Dispose of previously created meshes + if (previousMeshes && previousMeshes.length > 0) { + previousMeshes.forEach((mesh) => { + if (mesh && typeof mesh.dispose === 'function') { + mesh.dispose(); + } + }); + } + previousMeshes = []; // Clear the array + + // Re-execute the script with new inputs + const newResult = await runner.executeScript(exportedScript(), inputs); + previousMeshes = newResult.meshes || []; // Store new meshes + + buttonActivation(false); // Re-enable buttons + } +} + +// Function to update the labels on the HTML page +function updateLabels() { + document.getElementById('radius1').innerHTML = 'Radius 1 is ' + inputs.radius1; + document.getElementById('radius2').innerHTML = 'Radius 2 is ' + inputs.radius2; + document.getElementById('distance').innerHTML = 'Distance is ' + inputs.distance; +} + +// Function to disable/enable control buttons during script execution +function buttonActivation(disabled) { + const buttons = document.getElementsByTagName('button'); + for (let i = 0; i < buttons.length; i++) { + buttons.item(i).disabled = disabled; + } +} + +// Expose updateProp to the global window object so HTML onclick can find it +window.updateProp = updateProp; + +// Placeholder for your exported Rete script string +function exportedScript() { + // Replace this with the actual JavaScript string generated from your Rete editor + // for the parametric industrial part. + return '{"type":"rete","version":"0.X.X","script":"!async function(BitByBit,bitbybit,bitbybitRunnerResult,bitbybitRunnerInputs,Bit){ /* ... your very long exported Rete script ... */ }"}'; +} +`} + + +**Explanation of `script.js`:** + +1. **`window.inputs` Object:** Stores the current values for the parameters (`radius1`, `radius2`, `distance`) that will be passed to the Rete script. Making it a `window` property is a simple way to make it accessible globally within this script. +2. **`bounds` Object:** Defines minimum and maximum limits for each input parameter. +3. **`window.previousMeshes` Array:** This is crucial. It will store references to the 3D meshes created by the Rete script. Before re-running the script with new parameters, we'll dispose of these old meshes to prevent objects from overlapping and to manage memory. +4. **`updateLabels()`:** A helper function to update the text content of the `` elements in the HTML, reflecting the current parameter values. +5. **Camera Adjustment (Optional but Recommended):** + * `const { bitbybit, Bit } = await runner.run(runnerOptions);` + * After `runner.run()`, we now also destructure `bitbybit` (for API calls) and `Bit` (for accessing `Inputs` DTOs). + * We then adjust the active BabylonJS camera's position and target. This is done *once* after initializing the runner. If your Rete script *also* controls the camera, this step might be overridden, or you might choose to remove camera controls from the Rete script and manage it solely from your `script.js`. +6. **Initial Script Execution:** The Rete script is executed once with the initial `inputs`. The `scriptResult.meshes` (assuming your Rete script outputs meshes under a key named "meshes") are stored in `previousMeshes`. +7. **`async function updateProp(propName, increase)`:** + * This function is called when the `+` or `-` buttons in the HTML are clicked. + * It updates the corresponding value in the `inputs` object, checking against `bounds`. + * It calls `buttonActivation(true)` to temporarily disable all buttons, preventing rapid clicks while the script is processing. + * **Crucially, it iterates through `previousMeshes` and calls `mesh.dispose()` on each to remove them from the BabylonJS scene.** + * It then calls `await runner.executeScript(exportedScript(), inputs)` again with the *new* input values. + * The newly created meshes from this execution are stored in `previousMeshes`. + * `buttonActivation(false)` re-enables the buttons. +8. **`buttonActivation(disabled)`:** A utility to enable/disable all buttons on the page. +9. **`window.updateProp = updateProp;`:** Exposes the `updateProp` function to the global scope so it can be called by the `onclick` attributes in the HTML. +10. **`exportedScript()`:** **You must replace the placeholder string here with the actual, complete JavaScript string generated by the "Export to Runner" feature in your Bitbybit Rete editor for the parametric industrial part.** + +## Styling (`styles.css`) + +The CSS provided in the initial problem description can be used to style the page, buttons, and layout. + + +{`body { + margin: 0; + background-color: #1a1c1f; + color: white; + font-weight: 400; + font-family: 'IBM Plex Sans', sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + width: 100%; + height: 100%; +} + +button { + background-color: #1a1c1f; /* Match body or choose a button color */ + color: white; + border: 1px solid white; + border-radius: 5px; + padding: 5px 10px; /* Added padding for better click area */ + margin: 0 5px; /* Added margin for spacing */ + cursor: pointer; +} + +button:disabled { + opacity: 0.5; + cursor: not-allowed; +} + +.example { + margin-top: 50px; + margin-bottom: 50px; + margin-left: 300px; + margin-right: 300px; + display: flex; /* Added for centering content */ + flex-direction: column; + align-items: center; /* Center content horizontally */ +} + +@media (max-width: 1400px) { + .example { + margin-left: 100px; + margin-right: 100px; + } +} + +@media (max-width: 769px) { + .example { + margin-left: 20px; + margin-right: 20px; + } +} + +#myCanvas { + display: block; + outline: none; + border: 1px solid white; + border-radius: 5px; + width: 100%; /* Ensure canvas takes full width of its container */ + max-width: 800px; /* Optional: max width for very large screens */ + aspect-ratio: 16 / 9; /* Optional: maintain aspect ratio */ +} + +.logo { + margin-bottom: 20px; + display: flex; /* For aligning logo image and text */ + align-items: center; + text-decoration: none; +} + +.logo img { + width: 50px; + height: 50px; + margin-right: 10px; /* Space between logo image and text */ +} + +.myCanvasZone { + margin-top: 20px; + margin-bottom: 10px; + width: 100%; /* Ensure canvas zone takes available width */ + display: flex; /* For centering canvas if it has max-width */ + justify-content: center; +} + +a { + color: white; + vertical-align: middle; + text-decoration: underline; /* Make links more obvious */ +} + +.actions { + margin-top: 20px; /* Added margin-top */ + margin-bottom: 20px; + display: flex; /* For laying out control groups */ + flex-direction: column; + gap: 10px; /* Space between control groups */ + align-items: center; /* Center control groups */ +} + +.actions > div { /* Style for each control group (radius1, radius2, etc.) */ + display: flex; + align-items: center; +} + +.label { + text-align: center; + display: inline-block; + min-width: 150px; /* Increased min-width for better spacing */ + margin: 0 5px; /* Margin around label */ + font-size: 1.1em; /* Slightly larger label text */ +} +`} + + +## Conclusion + +This tutorial demonstrates a significant step up in using the Bitbybit Runner: creating dynamic, interactive 3D experiences on your website. You've learned how to: + +* Design Rete scripts that accept external inputs. +* Pass data from your HTML/JavaScript to the executed Rete script. +* Receive outputs (like 3D meshes) back from the script. +* Manage the lifecycle of 3D objects by disposing of old geometry before rendering new versions. +* Set up basic HTML controls to trigger these dynamic updates. + +This opens up a world of possibilities for building custom 3D tools and applications powered by your visual programs. \ No newline at end of file diff --git a/docs/learn/runners/live-examples/static-3d-model-script.mdx b/docs/learn/runners/live-examples/static-3d-model-script.mdx new file mode 100644 index 00000000..af9f4f73 --- /dev/null +++ b/docs/learn/runners/live-examples/static-3d-model-script.mdx @@ -0,0 +1,217 @@ +--- +sidebar_position: 1 +title: "Running Visual Scripts with Bitbybit Runner" +sidebar_label: "Alloy Wheel Rete Script" +description: "Learn how to export Rete visual programs as JavaScript and execute them on your own website using the Bitbybit Runner for BabylonJS." +tags: [runners, rete] +--- + +import BitByBitRenderCanvas from '@site/src/components/BitByBitRenderCanvas'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import CodeBlock from '@theme/CodeBlock'; +import Admonition from '@theme/Admonition'; + +# Running Visual Scripts with Bitbybit Runner + +The Bitbybit platform allows you to create complex 3D geometry and interactive scenes using visual programming environments like Rete. But what if you want to take these creations and run them on your own website, outside of the Bitbybit editor? That's where the **Bitbybit Runner** comes in! + +The Runner is a JavaScript library that can execute scripts exported from our visual editors (like Rete) directly in a browser environment, typically rendering the output using BabylonJS. This tutorial will guide you through the process of using an exported Rete script with the Bitbybit Runner. + +## The Rete Script: An Alloy Wheel Concept + +First, let's look at the Rete script we'll be working with. This script designs a concept for an alloy wheel using various OpenCascade (OCCT) operations. It involves creating lines, rotating them, dividing wires, lofting surfaces, and applying fillets to create a detailed 3D model. + +Below is an interactive preview of the Rete visual program. You can see the nodes and connections that define the geometry. + + + + +## Exporting the Script for the Runner + +When you are ready to use your Rete script outside the Bitbybit editor, you typically export it in a format that the runner can understand. This usually involves generating a JavaScript function that encapsulates the logic of your visual program. The Bitbybit platform provides an option to "Export to Runner", which gives you a JavaScript string for the Runner. You can even minify it. + +The core of this exported JavaScript will be a self-executing asynchronous function that takes instances of `BitByBit` (the core library), `bitbybit` (the API access object), `bitbybitRunnerResult` (for outputs), and `bitbybitRunnerInputs` (for inputs) as arguments. This static model does not need any of those as it does not take any inputs or produce any outputs for the runner. + +## Live Demo: Understanding the Runner in Action + +To see how all these pieces (HTML, Runner Library, and your exported script logic) come together, we've set up a live demonstration using StackBlitz. + +**Why is this StackBlitz demo important?** + +* **Simulates Your Website:** The StackBlitz environment effectively represents how this setup would work on **your own website**. It's a self-contained project with its own `index.html`, `styles.css`, and `script.js` – just like you would have if you were integrating this into your web application. +* **Practical Application:** It moves beyond theory and shows a tangible example of the runner in use. You can inspect the code, see the rendered 3D output, and understand the minimal requirements for embedding Bitbybit-generated content. +* **Deployment Context:** This demonstrates that projects built this way are not confined to the Bitbybit platform. You can deploy these kinds of projects on your own hosting providers (like Netlify, Vercel, GitHub Pages, or your own servers) and have full control over the user experience and integration with other web technologies. +* **Experimentation Sandbox:** StackBlitz allows you (and your users) to fork the example and experiment with changes to the HTML, CSS, or even the `runnerOptions` in `script.js` to see immediate results. + +By exploring the StackBlitz demo, you can gain confidence in how to take your visual programs from the Bitbybit editor and bring them to life anywhere on the web. + +
+ +
+ + +## Setting up Your HTML Page + +To use the runner on your own website, you'll need a basic HTML structure. + +```html title="index.html" + + + + Bitbybit Runner Example + + + + {/* Step 1: Include the Bitbybit Runner library */} + + {/* Step 2: Include your custom script that uses the runner */} + + + +
+ +

Runner Example - Alloy Wheel

+ {/* Step 3: Define a canvas element for rendering */} +
+ +
+ + Link to original Rete script. + +
+ + +``` + +```javascript title="script.js" +// Step 1: Define Runner Options +const runnerOptions = { + canvasId: 'myCanvas', // ID of the canvas element in your HTML + canvasZoneClass: 'myCanvasZone',// Class of the canvas container for resizing + enablePhysics: false, // Set to true if your script uses physics + enableOCCT: true, // Crucial: Set to true as our Rete script uses OCCT + enableJSCAD: false, // Set to true if using JSCAD + enableManifold: false, // Set to true if using Manifold + enableKeyEventListeners: false, // Enable if script needs to handle keyboard input (usually only Blockly or TypeScript...) + loadFonts: [], // Array of font file URLs if script uses custom 3D text fonts +}; + +// Step 2: Get the Runner Instance and Initialize +// The runner is globally available via window.bitbybitRunner after including the library. +const runner = window.bitbybitRunner.getRunnerInstance(); +await runner.run(runnerOptions); // Asynchronously initializes the runner and BabylonJS scene + +// Step 3: Define or Import Your Exported Rete Script +// This function returns the string of JavaScript code generated from your Rete editor. +// In a real application, this string might be loaded from a file, a database, or embedded directly. +function exportedScript() { + // This is the very long JavaScript string generated by "Export to Runner" from Rete. + // It starts with "!async function(e,t,s,n,r){..." where e=BitByBit, t=bitbybit, etc. + return '{"type":"rete","version":"0.15.9","script":"!async function(e,t,s,n,r){let a={};a={x:[0],y:[0],z:[1],...a};const o=[{result:e.HS.executeBasedOnType(a,!1,(e=>t.vector.vectorXYZ(e))),transformers:[]}]; ... (rest of the very long exported JS string) ... }(BitByBit,bitbybit,bitbybitRunnerResult,bitbybitRunnerInputs,Bit);"}' +} + +// Step 4: Execute the Script +// The second argument to executeScript can pass input values to your script if it's designed to accept them. +runner.executeScript(exportedScript(), {}); +``` + +We also needed some styling to make it pretty... :) + +```css title="styles.css" +body { + margin: 0; + background-color: #1a1c1f; + color: white; + font-weight: 400; + font-family: 'IBM Plex Sans', sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + width: 100%; + height: 100%; +} + +.example { + margin-top: 50px; + margin-bottom: 50px; + margin-left: 300px; + margin-right: 300px; +} + +@media(max-width:1400px) { + .example { + margin-left: 100px; + margin-right: 100px; + } +} + +@media(max-width:769px) { + .example { + margin-left: 20px; + margin-right: 20px; + } +} + +#myCanvas { + display: block; + outline: none; + border: 1px solid white; + border-radius: 5px; + width: 100%; +} + +.logo { + margin-bottom: 20px; +} + +.logo img { + width: 50px; + height: 50px; +} + +.myCanvasZone { + margin-top: 20px; + margin-bottom: 10px; +} + +a { + color: white; + vertical-align: middle; +} +``` + +## Conclusion + +In this tutorial, you've learned the essential steps to take a visual script created in Bitbybit's Rete editor and run it on an external webpage. We covered how to set up a basic HTML page, include the Bitbybit Runner library, configure runner options (crucially, enabling the OCCT kernel for our example), and finally, execute the exported JavaScript string representing your Rete program. This empowers you to integrate your powerful 3D creations and geometric algorithms directly into your own web projects. \ No newline at end of file diff --git a/docs/learn/runners/table-configurator-blockly.mdx b/docs/learn/runners/table-configurator-blockly.mdx index 1c68dd8e..8a740a7c 100644 --- a/docs/learn/runners/table-configurator-blockly.mdx +++ b/docs/learn/runners/table-configurator-blockly.mdx @@ -1,5 +1,5 @@ --- -sidebar_position: 6 +sidebar_position: 7 title: Building a 3D Table Configurator with Blockly & Bitbybit Runner sidebar_label: 3D Table Configurator (Blockly) description: Learn to build a simple 3D table configurator using the Blockly visual editor on Bitbybit and then deploy it as an interactive website on StackBlitz using Bitbybit Runner. diff --git a/docs/learn/runners/table-configurator-rete.mdx b/docs/learn/runners/table-configurator-rete.mdx index 9af834bb..e4042aec 100644 --- a/docs/learn/runners/table-configurator-rete.mdx +++ b/docs/learn/runners/table-configurator-rete.mdx @@ -1,5 +1,5 @@ --- -sidebar_position: 5 +sidebar_position: 6 title: Building a 3D Table Configurator with Rete & Bitbybit Runner sidebar_label: 3D Table Configurator (Rete) description: Learn to build a simple 3D table configurator using the Rete visual editor on Bitbybit and then deploy it as an interactive website on StackBlitz using Bitbybit Runner. diff --git a/docs/learn/runners/table-configurator-typescript.mdx b/docs/learn/runners/table-configurator-typescript.mdx index 47492850..660c2170 100644 --- a/docs/learn/runners/table-configurator-typescript.mdx +++ b/docs/learn/runners/table-configurator-typescript.mdx @@ -1,5 +1,5 @@ --- -sidebar_position: 7 +sidebar_position: 8 title: Building a 3D Table Configurator with TypeScript & Bitbybit Runner sidebar_label: 3D Table Configurator (TS) description: Learn to build a 3D table configurator by exporting TypeScript code from Bitbybit and integrating it into a web application on StackBlitz using Bitbybit Runner. diff --git a/docs/learn/tags.yml b/docs/learn/tags.yml index 0a7bc196..6d132ac5 100644 --- a/docs/learn/tags.yml +++ b/docs/learn/tags.yml @@ -111,4 +111,4 @@ shopify: 3d-bits: label: 3D Bits permalink: /3d-bits - description: 3D Bits is application that Bitbybit has developed for Shopify merchants - it can be installed on their webshops. \ No newline at end of file + description: 3D Bits is application that Bitbybit has developed for Shopify merchants - it can be installed on their webshops. diff --git a/docs/package-lock.json b/docs/package-lock.json index 42495e90..6ce14101 100644 --- a/docs/package-lock.json +++ b/docs/package-lock.json @@ -9,7 +9,6 @@ "version": "0.0.0", "dependencies": { "@docusaurus/core": "3.7.0", - "@docusaurus/plugin-google-gtag": "3.7.0", "@docusaurus/preset-classic": "3.7.0", "@mdx-js/react": "^3.0.0", "clsx": "^2.0.0", @@ -20,6 +19,7 @@ }, "devDependencies": { "@docusaurus/module-type-aliases": "3.7.0", + "@docusaurus/plugin-client-redirects": "3.7.0", "@docusaurus/tsconfig": "3.7.0", "@docusaurus/types": "3.7.0", "typescript": "~5.6.2" @@ -3137,6 +3137,30 @@ "react-dom": "*" } }, + "node_modules/@docusaurus/plugin-client-redirects": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-client-redirects/-/plugin-client-redirects-3.7.0.tgz", + "integrity": "sha512-6B4XAtE5ZVKOyhPgpgMkb7LwCkN+Hgd4vOnlbwR8nCdTQhLjz8MHbGlwwvZ/cay2SPNRX5KssqKAlcHVZP2m8g==", + "dev": true, + "dependencies": { + "@docusaurus/core": "3.7.0", + "@docusaurus/logger": "3.7.0", + "@docusaurus/utils": "3.7.0", + "@docusaurus/utils-common": "3.7.0", + "@docusaurus/utils-validation": "3.7.0", + "eta": "^2.2.0", + "fs-extra": "^11.1.1", + "lodash": "^4.17.21", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, "node_modules/@docusaurus/plugin-content-blog": { "version": "3.7.0", "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-blog/-/plugin-content-blog-3.7.0.tgz", diff --git a/docs/package.json b/docs/package.json index 6daa2872..bd6b078b 100644 --- a/docs/package.json +++ b/docs/package.json @@ -28,6 +28,7 @@ "@docusaurus/module-type-aliases": "3.7.0", "@docusaurus/tsconfig": "3.7.0", "@docusaurus/types": "3.7.0", + "@docusaurus/plugin-client-redirects": "3.7.0", "typescript": "~5.6.2" }, "browserslist": { diff --git a/docs/src/pages/index.tsx b/docs/src/pages/index.tsx index 8c522e80..66ec0563 100644 --- a/docs/src/pages/index.tsx +++ b/docs/src/pages/index.tsx @@ -1,6 +1,5 @@ import type {ReactNode} from "react"; import clsx from "clsx"; -import Link from "@docusaurus/Link"; import useDocusaurusContext from "@docusaurus/useDocusaurusContext"; import Layout from "@theme/Layout"; import HomepageFeatures from "@site/src/components/HomepageFeatures"; diff --git a/docs/static/img/learn-bitbybit-social-card.jpeg b/docs/static/img/learn-bitbybit-social-card.jpeg new file mode 100644 index 00000000..21eb5847 Binary files /dev/null and b/docs/static/img/learn-bitbybit-social-card.jpeg differ diff --git a/docs/static/img/learn-bitbybit-social-card.png b/docs/static/img/learn-bitbybit-social-card.png new file mode 100644 index 00000000..9eb7867a Binary files /dev/null and b/docs/static/img/learn-bitbybit-social-card.png differ diff --git a/docs/static/img/learn-bitbybit-social-card.xcf b/docs/static/img/learn-bitbybit-social-card.xcf new file mode 100644 index 00000000..8f6f25bf Binary files /dev/null and b/docs/static/img/learn-bitbybit-social-card.xcf differ diff --git a/examples/vite/babylonjs/hex-shell/index.html b/examples/vite/babylonjs/hex-shell/index.html index c7a81179..729d90ab 100644 --- a/examples/vite/babylonjs/hex-shell/index.html +++ b/examples/vite/babylonjs/hex-shell/index.html @@ -4,7 +4,7 @@ - Bitbybit & ThreeJS CAD Example + Bitbybit & BabylonJS Hex Shell Example
support the mission - subscribe
-
+ diff --git a/examples/vite/babylonjs/hex-shell/package-lock.json b/examples/vite/babylonjs/hex-shell/package-lock.json index bd467c19..01ce8597 100644 --- a/examples/vite/babylonjs/hex-shell/package-lock.json +++ b/examples/vite/babylonjs/hex-shell/package-lock.json @@ -1,7 +1,7 @@ { "name": "vite-typescript-starter", "version": "0.0.0", - "lockfileVersion": 3, + "lockfileVersion": 2, "requires": true, "packages": { "": { @@ -20,12 +20,14 @@ "node_modules/@babylonjs/core": { "version": "8.9.1", "resolved": "https://registry.npmjs.org/@babylonjs/core/-/core-8.9.1.tgz", - "integrity": "sha512-YJvsQgjEtBIKDJXCi+6rhPH5UJ46QbaMknO5fQGg8tT2PI5L6D+vfrhdZc1YNnzDrOmLkrkXF/Uy2CGdXFdT9Q==" + "integrity": "sha512-YJvsQgjEtBIKDJXCi+6rhPH5UJ46QbaMknO5fQGg8tT2PI5L6D+vfrhdZc1YNnzDrOmLkrkXF/Uy2CGdXFdT9Q==", + "license": "Apache-2.0" }, "node_modules/@babylonjs/gui": { "version": "8.9.1", "resolved": "https://registry.npmjs.org/@babylonjs/gui/-/gui-8.9.1.tgz", "integrity": "sha512-kYxPJ8C3HlNYrsKn3fPXJhQ8/BFUxMksBSNKQD+AsduEFWsMSlViYPdcMFh3oGpXEFZsqefoBoQe9xwN9L7brw==", + "license": "Apache-2.0", "peerDependencies": { "@babylonjs/core": "^8.0.0" } @@ -34,6 +36,7 @@ "version": "1.3.10", "resolved": "https://registry.npmjs.org/@babylonjs/havok/-/havok-1.3.10.tgz", "integrity": "sha512-ddF0LPBVmg+rmPaMmwTPA9FcHyUnrSsQqFoBbYbN51WMhEJQ+7gRFW3J5lML6lN9M/fbknh6bh1ZirZ2bU2B/w==", + "license": "MIT", "dependencies": { "@types/emscripten": "^1.39.6" } @@ -42,6 +45,7 @@ "version": "8.9.1", "resolved": "https://registry.npmjs.org/@babylonjs/loaders/-/loaders-8.9.1.tgz", "integrity": "sha512-8UolyusbjHoVVD2nNrqMMNS0a6OIiGrxPyzs6LYqCRFuXKXNhnFIPYCNU3WEBeD5Uc3+UQXgSaQpZudtjflFMw==", + "license": "Apache-2.0", "peerDependencies": { "@babylonjs/core": "^8.0.0", "babylonjs-gltf2interface": "^8.0.0" @@ -51,6 +55,7 @@ "version": "8.9.1", "resolved": "https://registry.npmjs.org/@babylonjs/materials/-/materials-8.9.1.tgz", "integrity": "sha512-/Ey/Kkb9JcqM1eJ7HpOcvMhCbE2CAPRJRBhTCe6jUQ08eG/nuOJHs5SRUBdP4X4DRxgDQWY0owFP2nLLWQKM6A==", + "license": "Apache-2.0", "peerDependencies": { "@babylonjs/core": "^8.6.0" } @@ -59,6 +64,7 @@ "version": "8.9.1", "resolved": "https://registry.npmjs.org/@babylonjs/serializers/-/serializers-8.9.1.tgz", "integrity": "sha512-iGsizPwkQp00PaBzZing+5/CBR/x2yCkGu7GsOx2uFfoutihtn8zy+u51rarE2O6TO2sNjxp/KxCMng48c8KWA==", + "license": "Apache-2.0", "peerDependencies": { "@babylonjs/core": "^8.0.0", "babylonjs-gltf2interface": "^8.0.0" @@ -68,6 +74,7 @@ "version": "0.20.4", "resolved": "https://registry.npmjs.org/@bitbybit-dev/babylonjs/-/babylonjs-0.20.4.tgz", "integrity": "sha512-tn+1VYQgz+6c2i16HpkIgWnIIRdnUCQKFdA701QGcKB59zJ67rU7Y8TIVTSVgPwJ9mJLpg1Co3bCVYEAyGCYXw==", + "license": "MIT", "dependencies": { "@babylonjs/core": "8.9.1", "@babylonjs/gui": "8.9.1", @@ -82,12 +89,14 @@ "node_modules/@bitbybit-dev/base": { "version": "0.20.4", "resolved": "https://registry.npmjs.org/@bitbybit-dev/base/-/base-0.20.4.tgz", - "integrity": "sha512-yMsOkUFrm9JIGC3Bs49bu1I/gqwQNK8nVO3XgesOpzZvVQOF5OTxCheiQnrqiUw9DiiPuKw1T0gXBMwThzwdOw==" + "integrity": "sha512-yMsOkUFrm9JIGC3Bs49bu1I/gqwQNK8nVO3XgesOpzZvVQOF5OTxCheiQnrqiUw9DiiPuKw1T0gXBMwThzwdOw==", + "license": "MIT" }, "node_modules/@bitbybit-dev/core": { "version": "0.20.4", "resolved": "https://registry.npmjs.org/@bitbybit-dev/core/-/core-0.20.4.tgz", "integrity": "sha512-T2hOHzvI+ikNxQRvhDyk/TeMCBhjZPY+wLmRSbYHiWnNGP5+3GCesZyb672XfEwPIWRH2kBS4vyp9R9fRnJujQ==", + "license": "MIT", "dependencies": { "@bitbybit-dev/base": "0.20.4", "@bitbybit-dev/jscad-worker": "0.20.4", @@ -102,6 +111,7 @@ "version": "0.20.4", "resolved": "https://registry.npmjs.org/@bitbybit-dev/jscad/-/jscad-0.20.4.tgz", "integrity": "sha512-e7/7Ag796rwn58H6Nu0lzhDkim+rJTqMWCqFZquNswoX2qqZXCv8azyOFE2LqfTvyIsEeJr/VEWIy2nvmtJnmg==", + "license": "MIT", "dependencies": { "@bitbybit-dev/base": "0.20.4", "@jscad/3mf-serializer": "2.1.12", @@ -115,6 +125,7 @@ "version": "0.20.4", "resolved": "https://registry.npmjs.org/@bitbybit-dev/jscad-worker/-/jscad-worker-0.20.4.tgz", "integrity": "sha512-DsjL2YO6urR8B/8LKYRrk4q9hAJE8oB+e5m+LDDBXbl7Vl0CHdC5ogPm6w07RcAHdSbMJouf2Ow7nGP/oOcjEg==", + "license": "MIT", "dependencies": { "@bitbybit-dev/jscad": "0.20.4", "rxjs": "7.5.5" @@ -124,6 +135,7 @@ "version": "0.20.4", "resolved": "https://registry.npmjs.org/@bitbybit-dev/manifold/-/manifold-0.20.4.tgz", "integrity": "sha512-rEGO8wOd/RUWPIRWdyE70w79JXhQ1iV6mACBuOH8/UD7+vf9wkk3KLWAYCzVPJP1nvx4+/SKCvU7e1JxEzq0Qw==", + "license": "MIT", "dependencies": { "manifold-3d": "3.0.0" } @@ -132,6 +144,7 @@ "version": "0.20.4", "resolved": "https://registry.npmjs.org/@bitbybit-dev/manifold-worker/-/manifold-worker-0.20.4.tgz", "integrity": "sha512-mwU87fg8M3p472dn/RiuveiPtq/IuOWCcoG0uismEE2g+rnciMrCSUSkXMkfXDCk9l0ZqoVfYg+dHVx0KBHBUg==", + "license": "MIT", "dependencies": { "@bitbybit-dev/manifold": "0.20.4", "rxjs": "7.5.5" @@ -141,6 +154,7 @@ "version": "0.20.4", "resolved": "https://registry.npmjs.org/@bitbybit-dev/occt/-/occt-0.20.4.tgz", "integrity": "sha512-Lxx4wsToS3EIiS2L3KjUh6Jpgvxsyxbh2Jt4raWhIbD9PSy1zRfMww9K7xFlawSMgq12WN1a0lV8ydKs1f5/zw==", + "license": "MIT", "dependencies": { "@bitbybit-dev/base": "0.20.4" } @@ -149,6 +163,7 @@ "version": "0.20.4", "resolved": "https://registry.npmjs.org/@bitbybit-dev/occt-worker/-/occt-worker-0.20.4.tgz", "integrity": "sha512-R5fiGteBSitv89Pz3XVgs+Vv0c1uH477oihkw1EUWLDTa7ypiXOohpjlKYFd/qAy3QCe8GEF3jDT+TK3dsQ+FA==", + "license": "MIT", "dependencies": { "@bitbybit-dev/occt": "0.20.4", "rxjs": "7.5.5" @@ -158,12 +173,13 @@ "version": "0.12.0", "resolved": "https://registry.npmjs.org/@dimforge/rapier3d-compat/-/rapier3d-compat-0.12.0.tgz", "integrity": "sha512-uekIGetywIgopfD97oDL5PfeezkFpNhwlzlaEYNOA0N6ghdsOvh/HYjSMek5Q2O1PYvRSDFcqFVJl4r4ZBwOow==", - "dev": true + "dev": true, + "license": "Apache-2.0" }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.4.tgz", - "integrity": "sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.3.tgz", + "integrity": "sha512-W8bFfPA8DowP8l//sxjJLSLkD8iEjMc7cBVyP+u4cEv9sM7mdUCkgsj+t0n/BWPFtv7WWCN5Yzj0N6FJNUUqBQ==", "cpu": [ "ppc64" ], @@ -177,9 +193,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.4.tgz", - "integrity": "sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.3.tgz", + "integrity": "sha512-PuwVXbnP87Tcff5I9ngV0lmiSu40xw1At6i3GsU77U7cjDDB4s0X2cyFuBiDa1SBk9DnvWwnGvVaGBqoFWPb7A==", "cpu": [ "arm" ], @@ -193,9 +209,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.4.tgz", - "integrity": "sha512-bBy69pgfhMGtCnwpC/x5QhfxAz/cBgQ9enbtwjf6V9lnPI/hMyT9iWpR1arm0l3kttTr4L0KSLpKmLp/ilKS9A==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.3.tgz", + "integrity": "sha512-XelR6MzjlZuBM4f5z2IQHK6LkK34Cvv6Rj2EntER3lwCBFdg6h2lKbtRjpTTsdEjD/WSe1q8UyPBXP1x3i/wYQ==", "cpu": [ "arm64" ], @@ -209,9 +225,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.4.tgz", - "integrity": "sha512-TVhdVtQIFuVpIIR282btcGC2oGQoSfZfmBdTip2anCaVYcqWlZXGcdcKIUklfX2wj0JklNYgz39OBqh2cqXvcQ==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.3.tgz", + "integrity": "sha512-ogtTpYHT/g1GWS/zKM0cc/tIebFjm1F9Aw1boQ2Y0eUQ+J89d0jFY//s9ei9jVIlkYi8AfOjiixcLJSGNSOAdQ==", "cpu": [ "x64" ], @@ -225,9 +241,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.4.tgz", - "integrity": "sha512-Y1giCfM4nlHDWEfSckMzeWNdQS31BQGs9/rouw6Ub91tkK79aIMTH3q9xHvzH8d0wDru5Ci0kWB8b3up/nl16g==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.3.tgz", + "integrity": "sha512-eESK5yfPNTqpAmDfFWNsOhmIOaQA59tAcF/EfYvo5/QWQCzXn5iUSOnqt3ra3UdzBv073ykTtmeLJZGt3HhA+w==", "cpu": [ "arm64" ], @@ -241,9 +257,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.4.tgz", - "integrity": "sha512-CJsry8ZGM5VFVeyUYB3cdKpd/H69PYez4eJh1W/t38vzutdjEjtP7hB6eLKBoOdxcAlCtEYHzQ/PJ/oU9I4u0A==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.3.tgz", + "integrity": "sha512-Kd8glo7sIZtwOLcPbW0yLpKmBNWMANZhrC1r6K++uDR2zyzb6AeOYtI6udbtabmQpFaxJ8uduXMAo1gs5ozz8A==", "cpu": [ "x64" ], @@ -257,9 +273,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.4.tgz", - "integrity": "sha512-yYq+39NlTRzU2XmoPW4l5Ifpl9fqSk0nAJYM/V/WUGPEFfek1epLHJIkTQM6bBs1swApjO5nWgvr843g6TjxuQ==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.3.tgz", + "integrity": "sha512-EJiyS70BYybOBpJth3M0KLOus0n+RRMKTYzhYhFeMwp7e/RaajXvP+BWlmEXNk6uk+KAu46j/kaQzr6au+JcIw==", "cpu": [ "arm64" ], @@ -273,9 +289,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.4.tgz", - "integrity": "sha512-0FgvOJ6UUMflsHSPLzdfDnnBBVoCDtBTVyn/MrWloUNvq/5SFmh13l3dvgRPkDihRxb77Y17MbqbCAa2strMQQ==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.3.tgz", + "integrity": "sha512-Q+wSjaLpGxYf7zC0kL0nDlhsfuFkoN+EXrx2KSB33RhinWzejOd6AvgmP5JbkgXKmjhmpfgKZq24pneodYqE8Q==", "cpu": [ "x64" ], @@ -289,9 +305,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.4.tgz", - "integrity": "sha512-kro4c0P85GMfFYqW4TWOpvmF8rFShbWGnrLqlzp4X1TNWjRY3JMYUfDCtOxPKOIY8B0WC8HN51hGP4I4hz4AaQ==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.3.tgz", + "integrity": "sha512-dUOVmAUzuHy2ZOKIHIKHCm58HKzFqd+puLaS424h6I85GlSDRZIA5ycBixb3mFgM0Jdh+ZOSB6KptX30DD8YOQ==", "cpu": [ "arm" ], @@ -305,9 +321,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.4.tgz", - "integrity": "sha512-+89UsQTfXdmjIvZS6nUnOOLoXnkUTB9hR5QAeLrQdzOSWZvNSAXAtcRDHWtqAUtAmv7ZM1WPOOeSxDzzzMogiQ==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.3.tgz", + "integrity": "sha512-xCUgnNYhRD5bb1C1nqrDV1PfkwgbswTTBRbAd8aH5PhYzikdf/ddtsYyMXFfGSsb/6t6QaPSzxtbfAZr9uox4A==", "cpu": [ "arm64" ], @@ -321,9 +337,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.4.tgz", - "integrity": "sha512-yTEjoapy8UP3rv8dB0ip3AfMpRbyhSN3+hY8mo/i4QXFeDxmiYbEKp3ZRjBKcOP862Ua4b1PDfwlvbuwY7hIGQ==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.3.tgz", + "integrity": "sha512-yplPOpczHOO4jTYKmuYuANI3WhvIPSVANGcNUeMlxH4twz/TeXuzEP41tGKNGWJjuMhotpGabeFYGAOU2ummBw==", "cpu": [ "ia32" ], @@ -337,9 +353,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.4.tgz", - "integrity": "sha512-NeqqYkrcGzFwi6CGRGNMOjWGGSYOpqwCjS9fvaUlX5s3zwOtn1qwg1s2iE2svBe4Q/YOG1q6875lcAoQK/F4VA==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.3.tgz", + "integrity": "sha512-P4BLP5/fjyihmXCELRGrLd793q/lBtKMQl8ARGpDxgzgIKJDRJ/u4r1A/HgpBpKpKZelGct2PGI4T+axcedf6g==", "cpu": [ "loong64" ], @@ -353,9 +369,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.4.tgz", - "integrity": "sha512-IcvTlF9dtLrfL/M8WgNI/qJYBENP3ekgsHbYUIzEzq5XJzzVEV/fXY9WFPfEEXmu3ck2qJP8LG/p3Q8f7Zc2Xg==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.3.tgz", + "integrity": "sha512-eRAOV2ODpu6P5divMEMa26RRqb2yUoYsuQQOuFUexUoQndm4MdpXXDBbUoKIc0iPa4aCO7gIhtnYomkn2x+bag==", "cpu": [ "mips64el" ], @@ -369,9 +385,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.4.tgz", - "integrity": "sha512-HOy0aLTJTVtoTeGZh4HSXaO6M95qu4k5lJcH4gxv56iaycfz1S8GO/5Jh6X4Y1YiI0h7cRyLi+HixMR+88swag==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.3.tgz", + "integrity": "sha512-ZC4jV2p7VbzTlnl8nZKLcBkfzIf4Yad1SJM4ZMKYnJqZFD4rTI+pBG65u8ev4jk3/MPwY9DvGn50wi3uhdaghg==", "cpu": [ "ppc64" ], @@ -385,9 +401,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.4.tgz", - "integrity": "sha512-i8JUDAufpz9jOzo4yIShCTcXzS07vEgWzyX3NH2G7LEFVgrLEhjwL3ajFE4fZI3I4ZgiM7JH3GQ7ReObROvSUA==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.3.tgz", + "integrity": "sha512-LDDODcFzNtECTrUUbVCs6j9/bDVqy7DDRsuIXJg6so+mFksgwG7ZVnTruYi5V+z3eE5y+BJZw7VvUadkbfg7QA==", "cpu": [ "riscv64" ], @@ -401,9 +417,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.4.tgz", - "integrity": "sha512-jFnu+6UbLlzIjPQpWCNh5QtrcNfMLjgIavnwPQAfoGx4q17ocOU9MsQ2QVvFxwQoWpZT8DvTLooTvmOQXkO51g==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.3.tgz", + "integrity": "sha512-s+w/NOY2k0yC2p9SLen+ymflgcpRkvwwa02fqmAwhBRI3SC12uiS10edHHXlVWwfAagYSY5UpmT/zISXPMW3tQ==", "cpu": [ "s390x" ], @@ -417,9 +433,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.4.tgz", - "integrity": "sha512-6e0cvXwzOnVWJHq+mskP8DNSrKBr1bULBvnFLpc1KY+d+irZSgZ02TGse5FsafKS5jg2e4pbvK6TPXaF/A6+CA==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.3.tgz", + "integrity": "sha512-nQHDz4pXjSDC6UfOE1Fw9Q8d6GCAd9KdvMZpfVGWSJztYCarRgSDfOVBY5xwhQXseiyxapkiSJi/5/ja8mRFFA==", "cpu": [ "x64" ], @@ -433,9 +449,9 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.4.tgz", - "integrity": "sha512-vUnkBYxZW4hL/ie91hSqaSNjulOnYXE1VSLusnvHg2u3jewJBz3YzB9+oCw8DABeVqZGg94t9tyZFoHma8gWZQ==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.3.tgz", + "integrity": "sha512-1QaLtOWq0mzK6tzzp0jRN3eccmN3hezey7mhLnzC6oNlJoUJz4nym5ZD7mDnS/LZQgkrhEbEiTn515lPeLpgWA==", "cpu": [ "arm64" ], @@ -449,9 +465,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.4.tgz", - "integrity": "sha512-XAg8pIQn5CzhOB8odIcAm42QsOfa98SBeKUdo4xa8OvX8LbMZqEtgeWE9P/Wxt7MlG2QqvjGths+nq48TrUiKw==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.3.tgz", + "integrity": "sha512-i5Hm68HXHdgv8wkrt+10Bc50zM0/eonPb/a/OFVfB6Qvpiirco5gBA5bz7S2SHuU+Y4LWn/zehzNX14Sp4r27g==", "cpu": [ "x64" ], @@ -465,9 +481,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.4.tgz", - "integrity": "sha512-Ct2WcFEANlFDtp1nVAXSNBPDxyU+j7+tId//iHXU2f/lN5AmO4zLyhDcpR5Cz1r08mVxzt3Jpyt4PmXQ1O6+7A==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.3.tgz", + "integrity": "sha512-zGAVApJEYTbOC6H/3QBr2mq3upG/LBEXr85/pTtKiv2IXcgKV0RT0QA/hSXZqSvLEpXeIxah7LczB4lkiYhTAQ==", "cpu": [ "arm64" ], @@ -481,9 +497,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.4.tgz", - "integrity": "sha512-xAGGhyOQ9Otm1Xu8NT1ifGLnA6M3sJxZ6ixylb+vIUVzvvd6GOALpwQrYrtlPouMqd/vSbgehz6HaVk4+7Afhw==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.3.tgz", + "integrity": "sha512-fpqctI45NnCIDKBH5AXQBsD0NDPbEFczK98hk/aa6HJxbl+UtLkJV2+Bvy5hLSLk3LHmqt0NTkKNso1A9y1a4w==", "cpu": [ "x64" ], @@ -497,9 +513,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.4.tgz", - "integrity": "sha512-Mw+tzy4pp6wZEK0+Lwr76pWLjrtjmJyUB23tHKqEDP74R3q95luY/bXqXZeYl4NYlvwOqoRKlInQialgCKy67Q==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.3.tgz", + "integrity": "sha512-ROJhm7d8bk9dMCUZjkS8fgzsPAZEjtRJqCAmVgB0gMrvG7hfmPmz9k1rwO4jSiblFjYmNvbECL9uhaPzONMfgA==", "cpu": [ "x64" ], @@ -513,9 +529,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.4.tgz", - "integrity": "sha512-AVUP428VQTSddguz9dO9ngb+E5aScyg7nOeJDrF1HPYu555gmza3bDGMPhmVXL8svDSoqPCsCPjb265yG/kLKQ==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.3.tgz", + "integrity": "sha512-YWcow8peiHpNBiIXHwaswPnAXLsLVygFwCB3A7Bh5jRkIBFWHGmNQ48AlX4xDvQNoMZlPYzjVOQDYEzWCqufMQ==", "cpu": [ "arm64" ], @@ -529,9 +545,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.4.tgz", - "integrity": "sha512-i1sW+1i+oWvQzSgfRcxxG2k4I9n3O9NRqy8U+uugaT2Dy7kLO9Y7wI72haOahxceMX8hZAzgGou1FhndRldxRg==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.3.tgz", + "integrity": "sha512-qspTZOIGoXVS4DpNqUYUs9UxVb04khS1Degaw/MnfMe7goQ3lTfQ13Vw4qY/Nj0979BGvMRpAYbs/BAxEvU8ew==", "cpu": [ "ia32" ], @@ -545,9 +561,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.4.tgz", - "integrity": "sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.3.tgz", + "integrity": "sha512-ICgUR+kPimx0vvRzf+N/7L7tVSQeE3BYY+NhHRHXS1kBuPO7z2+7ea2HbhDyZdTephgvNvKrlDDKUexuCVBVvg==", "cpu": [ "x64" ], @@ -564,6 +580,7 @@ "version": "2.1.12", "resolved": "https://registry.npmjs.org/@jscad/3mf-serializer/-/3mf-serializer-2.1.12.tgz", "integrity": "sha512-+rxAIKIHCpaplupwwsdXtG1IdimPXFFB45nrjy6gdFHi36bEQW6y/RQD/ngenRiKnYSxu7/M0LatHcjve8z64A==", + "license": "MIT", "dependencies": { "@jscad/array-utils": "2.1.4", "@jscad/modeling": "2.12.3", @@ -574,12 +591,14 @@ "node_modules/@jscad/array-utils": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/@jscad/array-utils/-/array-utils-2.1.4.tgz", - "integrity": "sha512-c31r4zSKsE+4Xfwk2V8monDA0hx5G89QGzaakWVUvuGNowYS9WSsYCwHiTIXodjR+HEnDu4okQ7k/whmP0Ne2g==" + "integrity": "sha512-c31r4zSKsE+4Xfwk2V8monDA0hx5G89QGzaakWVUvuGNowYS9WSsYCwHiTIXodjR+HEnDu4okQ7k/whmP0Ne2g==", + "license": "MIT" }, "node_modules/@jscad/dxf-serializer": { "version": "2.1.18", "resolved": "https://registry.npmjs.org/@jscad/dxf-serializer/-/dxf-serializer-2.1.18.tgz", "integrity": "sha512-T5Qe2jbEphcWAk7GaOY8PCMD4DPhTm6gWk/MPJCExphhnUwJqcU/1RiMb5hiD+N6hHzmlxD59I8QTjlp9LbLSA==", + "license": "MIT", "dependencies": { "@jscad/array-utils": "2.1.4", "@jscad/modeling": "2.12.3" @@ -588,17 +607,20 @@ "node_modules/@jscad/io-utils": { "version": "2.0.28", "resolved": "https://registry.npmjs.org/@jscad/io-utils/-/io-utils-2.0.28.tgz", - "integrity": "sha512-spXh37wAgmwjKztoH/HANLgImcqRHX5+H/cRIxPfpqDIWvu7I5bRg2ZTwh25SYlKIzxPk4qX5Nu7Ax5+Kg+QXQ==" + "integrity": "sha512-spXh37wAgmwjKztoH/HANLgImcqRHX5+H/cRIxPfpqDIWvu7I5bRg2ZTwh25SYlKIzxPk4qX5Nu7Ax5+Kg+QXQ==", + "license": "MIT" }, "node_modules/@jscad/modeling": { "version": "2.12.3", "resolved": "https://registry.npmjs.org/@jscad/modeling/-/modeling-2.12.3.tgz", - "integrity": "sha512-DnAacXq3zhlYWIixGlFD7RMpgZAMuCaMZNQov0NaoFfs2GaBuTC5eqkqKcEVbhEerBmTllbjjF5IXjJMt9jcOA==" + "integrity": "sha512-DnAacXq3zhlYWIixGlFD7RMpgZAMuCaMZNQov0NaoFfs2GaBuTC5eqkqKcEVbhEerBmTllbjjF5IXjJMt9jcOA==", + "license": "MIT" }, "node_modules/@jscad/stl-serializer": { "version": "2.1.18", "resolved": "https://registry.npmjs.org/@jscad/stl-serializer/-/stl-serializer-2.1.18.tgz", "integrity": "sha512-pz++TRjHI7jBPnnxQUi4B/uYUG3yCDsKlw8+xL2kumwjb+auc6Ng6Rnr/GqUTkgHrnGut08wg/8AekyWjvBwYg==", + "license": "MIT", "dependencies": { "@jscad/array-utils": "2.1.4", "@jscad/modeling": "2.12.3" @@ -608,6 +630,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/@jsep-plugin/assignment/-/assignment-1.3.0.tgz", "integrity": "sha512-VVgV+CXrhbMI3aSusQyclHkenWSAm95WaiKrMxRFam3JSUiIaQjoMIw2sEs/OX4XifnqeQUN4DYbJjlA8EfktQ==", + "license": "MIT", "engines": { "node": ">= 10.16.0" }, @@ -619,6 +642,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/@jsep-plugin/regex/-/regex-1.0.4.tgz", "integrity": "sha512-q7qL4Mgjs1vByCaTnDFcBnV9HS7GVPJX5vyVoCgZHNSC9rjwIlmbXG5sUuorR5ndfHAIlJ8pVStxvjXHbNvtUg==", + "license": "MIT", "engines": { "node": ">= 10.16.0" }, @@ -627,9 +651,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.41.0.tgz", - "integrity": "sha512-KxN+zCjOYHGwCl4UCtSfZ6jrq/qi88JDUtiEFk8LELEHq2Egfc/FgW+jItZiOLRuQfb/3xJSgFuNPC9jzggX+A==", + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.40.1.tgz", + "integrity": "sha512-kxz0YeeCrRUHz3zyqvd7n+TVRlNyTifBsmnmNPtk3hQURUyG9eAB+usz6DAwagMusjx/zb3AjvDUvhFGDAexGw==", "cpu": [ "arm" ], @@ -640,9 +664,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.41.0.tgz", - "integrity": "sha512-yDvqx3lWlcugozax3DItKJI5j05B0d4Kvnjx+5mwiUpWramVvmAByYigMplaoAQ3pvdprGCTCE03eduqE/8mPQ==", + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.40.1.tgz", + "integrity": "sha512-PPkxTOisoNC6TpnDKatjKkjRMsdaWIhyuMkA4UsBXT9WEZY4uHezBTjs6Vl4PbqQQeu6oION1w2voYZv9yquCw==", "cpu": [ "arm64" ], @@ -653,9 +677,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.41.0.tgz", - "integrity": "sha512-2KOU574vD3gzcPSjxO0eyR5iWlnxxtmW1F5CkNOHmMlueKNCQkxR6+ekgWyVnz6zaZihpUNkGxjsYrkTJKhkaw==", + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.40.1.tgz", + "integrity": "sha512-VWXGISWFY18v/0JyNUy4A46KCFCb9NVsH+1100XP31lud+TzlezBbz24CYzbnA4x6w4hx+NYCXDfnvDVO6lcAA==", "cpu": [ "arm64" ], @@ -666,9 +690,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.41.0.tgz", - "integrity": "sha512-gE5ACNSxHcEZyP2BA9TuTakfZvULEW4YAOtxl/A/YDbIir/wPKukde0BNPlnBiP88ecaN4BJI2TtAd+HKuZPQQ==", + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.40.1.tgz", + "integrity": "sha512-nIwkXafAI1/QCS7pxSpv/ZtFW6TXcNUEHAIA9EIyw5OzxJZQ1YDrX+CL6JAIQgZ33CInl1R6mHet9Y/UZTg2Bw==", "cpu": [ "x64" ], @@ -679,9 +703,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.41.0.tgz", - "integrity": "sha512-GSxU6r5HnWij7FoSo7cZg3l5GPg4HFLkzsFFh0N/b16q5buW1NAWuCJ+HMtIdUEi6XF0qH+hN0TEd78laRp7Dg==", + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.40.1.tgz", + "integrity": "sha512-BdrLJ2mHTrIYdaS2I99mriyJfGGenSaP+UwGi1kB9BLOCu9SR8ZpbkmmalKIALnRw24kM7qCN0IOm6L0S44iWw==", "cpu": [ "arm64" ], @@ -692,9 +716,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.41.0.tgz", - "integrity": "sha512-KGiGKGDg8qLRyOWmk6IeiHJzsN/OYxO6nSbT0Vj4MwjS2XQy/5emsmtoqLAabqrohbgLWJ5GV3s/ljdrIr8Qjg==", + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.40.1.tgz", + "integrity": "sha512-VXeo/puqvCG8JBPNZXZf5Dqq7BzElNJzHRRw3vjBE27WujdzuOPecDPc/+1DcdcTptNBep3861jNq0mYkT8Z6Q==", "cpu": [ "x64" ], @@ -705,9 +729,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.41.0.tgz", - "integrity": "sha512-46OzWeqEVQyX3N2/QdiU/CMXYDH/lSHpgfBkuhl3igpZiaB3ZIfSjKuOnybFVBQzjsLwkus2mjaESy8H41SzvA==", + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.40.1.tgz", + "integrity": "sha512-ehSKrewwsESPt1TgSE/na9nIhWCosfGSFqv7vwEtjyAqZcvbGIg4JAcV7ZEh2tfj/IlfBeZjgOXm35iOOjadcg==", "cpu": [ "arm" ], @@ -718,9 +742,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.41.0.tgz", - "integrity": "sha512-lfgW3KtQP4YauqdPpcUZHPcqQXmTmH4nYU0cplNeW583CMkAGjtImw4PKli09NFi2iQgChk4e9erkwlfYem6Lg==", + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.40.1.tgz", + "integrity": "sha512-m39iO/aaurh5FVIu/F4/Zsl8xppd76S4qoID8E+dSRQvTyZTOI2gVk3T4oqzfq1PtcvOfAVlwLMK3KRQMaR8lg==", "cpu": [ "arm" ], @@ -731,9 +755,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.41.0.tgz", - "integrity": "sha512-nn8mEyzMbdEJzT7cwxgObuwviMx6kPRxzYiOl6o/o+ChQq23gfdlZcUNnt89lPhhz3BYsZ72rp0rxNqBSfqlqw==", + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.40.1.tgz", + "integrity": "sha512-Y+GHnGaku4aVLSgrT0uWe2o2Rq8te9hi+MwqGF9r9ORgXhmHK5Q71N757u0F8yU1OIwUIFy6YiJtKjtyktk5hg==", "cpu": [ "arm64" ], @@ -744,9 +768,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.41.0.tgz", - "integrity": "sha512-l+QK99je2zUKGd31Gh+45c4pGDAqZSuWQiuRFCdHYC2CSiO47qUWsCcenrI6p22hvHZrDje9QjwSMAFL3iwXwQ==", + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.40.1.tgz", + "integrity": "sha512-jEwjn3jCA+tQGswK3aEWcD09/7M5wGwc6+flhva7dsQNRZZTe30vkalgIzV4tjkopsTS9Jd7Y1Bsj6a4lzz8gQ==", "cpu": [ "arm64" ], @@ -757,9 +781,9 @@ ] }, "node_modules/@rollup/rollup-linux-loongarch64-gnu": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.41.0.tgz", - "integrity": "sha512-WbnJaxPv1gPIm6S8O/Wg+wfE/OzGSXlBMbOe4ie+zMyykMOeqmgD1BhPxZQuDqwUN+0T/xOFtL2RUWBspnZj3w==", + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.40.1.tgz", + "integrity": "sha512-ySyWikVhNzv+BV/IDCsrraOAZ3UaC8SZB67FZlqVwXwnFhPihOso9rPOxzZbjp81suB1O2Topw+6Ug3JNegejQ==", "cpu": [ "loong64" ], @@ -770,9 +794,9 @@ ] }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.41.0.tgz", - "integrity": "sha512-eRDWR5t67/b2g8Q/S8XPi0YdbKcCs4WQ8vklNnUYLaSWF+Cbv2axZsp4jni6/j7eKvMLYCYdcsv8dcU+a6QNFg==", + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.40.1.tgz", + "integrity": "sha512-BvvA64QxZlh7WZWqDPPdt0GH4bznuL6uOO1pmgPnnv86rpUpc8ZxgZwcEgXvo02GRIZX1hQ0j0pAnhwkhwPqWg==", "cpu": [ "ppc64" ], @@ -783,9 +807,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.41.0.tgz", - "integrity": "sha512-TWrZb6GF5jsEKG7T1IHwlLMDRy2f3DPqYldmIhnA2DVqvvhY2Ai184vZGgahRrg8k9UBWoSlHv+suRfTN7Ua4A==", + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.40.1.tgz", + "integrity": "sha512-EQSP+8+1VuSulm9RKSMKitTav89fKbHymTf25n5+Yr6gAPZxYWpj3DzAsQqoaHAk9YX2lwEyAf9S4W8F4l3VBQ==", "cpu": [ "riscv64" ], @@ -796,9 +820,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.41.0.tgz", - "integrity": "sha512-ieQljaZKuJpmWvd8gW87ZmSFwid6AxMDk5bhONJ57U8zT77zpZ/TPKkU9HpnnFrM4zsgr4kiGuzbIbZTGi7u9A==", + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.40.1.tgz", + "integrity": "sha512-n/vQ4xRZXKuIpqukkMXZt9RWdl+2zgGNx7Uda8NtmLJ06NL8jiHxUawbwC+hdSq1rrw/9CghCpEONor+l1e2gA==", "cpu": [ "riscv64" ], @@ -809,9 +833,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.41.0.tgz", - "integrity": "sha512-/L3pW48SxrWAlVsKCN0dGLB2bi8Nv8pr5S5ocSM+S0XCn5RCVCXqi8GVtHFsOBBCSeR+u9brV2zno5+mg3S4Aw==", + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.40.1.tgz", + "integrity": "sha512-h8d28xzYb98fMQKUz0w2fMc1XuGzLLjdyxVIbhbil4ELfk5/orZlSTpF/xdI9C8K0I8lCkq+1En2RJsawZekkg==", "cpu": [ "s390x" ], @@ -822,9 +846,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.41.0.tgz", - "integrity": "sha512-XMLeKjyH8NsEDCRptf6LO8lJk23o9wvB+dJwcXMaH6ZQbbkHu2dbGIUindbMtRN6ux1xKi16iXWu6q9mu7gDhQ==", + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.40.1.tgz", + "integrity": "sha512-XiK5z70PEFEFqcNj3/zRSz/qX4bp4QIraTy9QjwJAb/Z8GM7kVUsD0Uk8maIPeTyPCP03ChdI+VVmJriKYbRHQ==", "cpu": [ "x64" ], @@ -835,9 +859,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.41.0.tgz", - "integrity": "sha512-m/P7LycHZTvSQeXhFmgmdqEiTqSV80zn6xHaQ1JSqwCtD1YGtwEK515Qmy9DcB2HK4dOUVypQxvhVSy06cJPEg==", + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.40.1.tgz", + "integrity": "sha512-2BRORitq5rQ4Da9blVovzNCMaUlyKrzMSvkVR0D4qPuOy/+pMCrh1d7o01RATwVy+6Fa1WBw+da7QPeLWU/1mQ==", "cpu": [ "x64" ], @@ -848,9 +872,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.41.0.tgz", - "integrity": "sha512-4yodtcOrFHpbomJGVEqZ8fzD4kfBeCbpsUy5Pqk4RluXOdsWdjLnjhiKy2w3qzcASWd04fp52Xz7JKarVJ5BTg==", + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.40.1.tgz", + "integrity": "sha512-b2bcNm9Kbde03H+q+Jjw9tSfhYkzrDUf2d5MAd1bOJuVplXvFhWz7tRtWvD8/ORZi7qSCy0idW6tf2HgxSXQSg==", "cpu": [ "arm64" ], @@ -861,9 +885,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.41.0.tgz", - "integrity": "sha512-tmazCrAsKzdkXssEc65zIE1oC6xPHwfy9d5Ta25SRCDOZS+I6RypVVShWALNuU9bxIfGA0aqrmzlzoM5wO5SPQ==", + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.40.1.tgz", + "integrity": "sha512-DfcogW8N7Zg7llVEfpqWMZcaErKfsj9VvmfSyRjCyo4BI3wPEfrzTtJkZG6gKP/Z92wFm6rz2aDO7/JfiR/whA==", "cpu": [ "ia32" ], @@ -874,9 +898,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.41.0.tgz", - "integrity": "sha512-h1J+Yzjo/X+0EAvR2kIXJDuTuyT7drc+t2ALY0nIcGPbTatNOf0VWdhEA2Z4AAjv6X1NJV7SYo5oCTYRJhSlVA==", + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.40.1.tgz", + "integrity": "sha512-ECyOuDeH3C1I8jH2MK1RtBJW+YPMvSfT0a5NN0nHfQYnDSJ6tUiZH3gzwVP5/Kfh/+Tt7tpWVF9LXNTnhTJ3kA==", "cpu": [ "x64" ], @@ -890,12 +914,14 @@ "version": "23.1.3", "resolved": "https://registry.npmjs.org/@tweenjs/tween.js/-/tween.js-23.1.3.tgz", "integrity": "sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/emscripten": { "version": "1.40.1", "resolved": "https://registry.npmjs.org/@types/emscripten/-/emscripten-1.40.1.tgz", - "integrity": "sha512-sr53lnYkQNhjHNN0oJDdUm5564biioI5DuOpycufDVK7D3y+GR3oUswe2rlwY1nPNyusHbrJ9WoTyIHl4/Bpwg==" + "integrity": "sha512-sr53lnYkQNhjHNN0oJDdUm5564biioI5DuOpycufDVK7D3y+GR3oUswe2rlwY1nPNyusHbrJ9WoTyIHl4/Bpwg==", + "license": "MIT" }, "node_modules/@types/estree": { "version": "1.0.7", @@ -904,16 +930,18 @@ "dev": true }, "node_modules/@types/stats.js": { - "version": "0.17.4", - "resolved": "https://registry.npmjs.org/@types/stats.js/-/stats.js-0.17.4.tgz", - "integrity": "sha512-jIBvWWShCvlBqBNIZt0KAshWpvSjhkwkEu4ZUcASoAvhmrgAUI2t1dXrjSL4xXVLB4FznPrIsX3nKXFl/Dt4vA==", - "dev": true + "version": "0.17.3", + "resolved": "https://registry.npmjs.org/@types/stats.js/-/stats.js-0.17.3.tgz", + "integrity": "sha512-pXNfAD3KHOdif9EQXZ9deK82HVNaXP5ZIF5RP2QG6OQFNTaY2YIetfrE9t528vEreGQvEPRDDc8muaoYeK0SxQ==", + "dev": true, + "license": "MIT" }, "node_modules/@types/three": { "version": "0.176.0", "resolved": "https://registry.npmjs.org/@types/three/-/three-0.176.0.tgz", "integrity": "sha512-FwfPXxCqOtP7EdYMagCFePNKoG1AGBDUEVKtluv2BTVRpSt7b+X27xNsirPCTCqY1pGYsPUzaM3jgWP7dXSxlw==", "dev": true, + "license": "MIT", "dependencies": { "@dimforge/rapier3d-compat": "^0.12.0", "@tweenjs/tween.js": "~23.1.3", @@ -928,30 +956,35 @@ "version": "0.8.2", "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz", "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/webxr": { "version": "0.5.22", "resolved": "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.22.tgz", "integrity": "sha512-Vr6Stjv5jPRqH690f5I5GLjVk8GSsoQSYJ2FVd/3jJF7KaqfwPi3ehfBS96mlQ2kPCwZaX6U0rG2+NGHBKkA/A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@webgpu/types": { "version": "0.1.60", "resolved": "https://registry.npmjs.org/@webgpu/types/-/types-0.1.60.tgz", "integrity": "sha512-8B/tdfRFKdrnejqmvq95ogp8tf52oZ51p3f4QD5m5Paey/qlX4Rhhy5Y8tgFMi7Ms70HzcMMw3EQjH/jdhTwlA==", - "dev": true + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/babylonjs-gltf2interface": { - "version": "8.9.1", - "resolved": "https://registry.npmjs.org/babylonjs-gltf2interface/-/babylonjs-gltf2interface-8.9.1.tgz", - "integrity": "sha512-7GjEcvwL+d/lJ058J7rYTM96reekIq/kjg6SkM7NG6+Krj7UM3HMeJkAhwj22dCBfOs2/RzjFSGleEhh5qjq5g==", + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/babylonjs-gltf2interface/-/babylonjs-gltf2interface-8.10.0.tgz", + "integrity": "sha512-ExGp0TqBzX9ZnWryYSccNZJnFHAby4XHYhwvsCkOJy+3+uDb56x9Q7Ao1eGuncepzclSbzrxohuOhalPgm6dAw==", + "license": "Apache-2.0", "peer": true }, "node_modules/bindings": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "license": "MIT", "optional": true, "dependencies": { "file-uri-to-path": "1.0.0" @@ -960,12 +993,13 @@ "node_modules/earcut": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/earcut/-/earcut-2.2.3.tgz", - "integrity": "sha512-iRDI1QeCQIhMCZk48DRDMVgQSSBDmbzzNhnxIo+pwx3swkfjMh6vh0nWLq1NdvGHLKH6wIrAM3vQWeTj6qeoug==" + "integrity": "sha512-iRDI1QeCQIhMCZk48DRDMVgQSSBDmbzzNhnxIo+pwx3swkfjMh6vh0nWLq1NdvGHLKH6wIrAM3vQWeTj6qeoug==", + "license": "ISC" }, "node_modules/esbuild": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.4.tgz", - "integrity": "sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.3.tgz", + "integrity": "sha512-qKA6Pvai73+M2FtftpNKRxJ78GIjmFXFxd/1DVBqGo/qNhLSfv+G12n9pNoWdytJC8U00TrViOwpjT0zgqQS8Q==", "dev": true, "hasInstallScript": true, "bin": { @@ -975,31 +1009,31 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.4", - "@esbuild/android-arm": "0.25.4", - "@esbuild/android-arm64": "0.25.4", - "@esbuild/android-x64": "0.25.4", - "@esbuild/darwin-arm64": "0.25.4", - "@esbuild/darwin-x64": "0.25.4", - "@esbuild/freebsd-arm64": "0.25.4", - "@esbuild/freebsd-x64": "0.25.4", - "@esbuild/linux-arm": "0.25.4", - "@esbuild/linux-arm64": "0.25.4", - "@esbuild/linux-ia32": "0.25.4", - "@esbuild/linux-loong64": "0.25.4", - "@esbuild/linux-mips64el": "0.25.4", - "@esbuild/linux-ppc64": "0.25.4", - "@esbuild/linux-riscv64": "0.25.4", - "@esbuild/linux-s390x": "0.25.4", - "@esbuild/linux-x64": "0.25.4", - "@esbuild/netbsd-arm64": "0.25.4", - "@esbuild/netbsd-x64": "0.25.4", - "@esbuild/openbsd-arm64": "0.25.4", - "@esbuild/openbsd-x64": "0.25.4", - "@esbuild/sunos-x64": "0.25.4", - "@esbuild/win32-arm64": "0.25.4", - "@esbuild/win32-ia32": "0.25.4", - "@esbuild/win32-x64": "0.25.4" + "@esbuild/aix-ppc64": "0.25.3", + "@esbuild/android-arm": "0.25.3", + "@esbuild/android-arm64": "0.25.3", + "@esbuild/android-x64": "0.25.3", + "@esbuild/darwin-arm64": "0.25.3", + "@esbuild/darwin-x64": "0.25.3", + "@esbuild/freebsd-arm64": "0.25.3", + "@esbuild/freebsd-x64": "0.25.3", + "@esbuild/linux-arm": "0.25.3", + "@esbuild/linux-arm64": "0.25.3", + "@esbuild/linux-ia32": "0.25.3", + "@esbuild/linux-loong64": "0.25.3", + "@esbuild/linux-mips64el": "0.25.3", + "@esbuild/linux-ppc64": "0.25.3", + "@esbuild/linux-riscv64": "0.25.3", + "@esbuild/linux-s390x": "0.25.3", + "@esbuild/linux-x64": "0.25.3", + "@esbuild/netbsd-arm64": "0.25.3", + "@esbuild/netbsd-x64": "0.25.3", + "@esbuild/openbsd-arm64": "0.25.3", + "@esbuild/openbsd-x64": "0.25.3", + "@esbuild/sunos-x64": "0.25.3", + "@esbuild/win32-arm64": "0.25.3", + "@esbuild/win32-ia32": "0.25.3", + "@esbuild/win32-x64": "0.25.3" } }, "node_modules/fdir": { @@ -1019,12 +1053,14 @@ "node_modules/fflate": { "version": "0.7.3", "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.7.3.tgz", - "integrity": "sha512-0Zz1jOzJWERhyhsimS54VTqOteCNwRtIlh8isdL0AXLo0g7xNTfTL7oWrkmCnPhZGocKIkWHBistBrrpoNH3aw==" + "integrity": "sha512-0Zz1jOzJWERhyhsimS54VTqOteCNwRtIlh8isdL0AXLo0g7xNTfTL7oWrkmCnPhZGocKIkWHBistBrrpoNH3aw==", + "license": "MIT" }, "node_modules/file-uri-to-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "license": "MIT", "optional": true }, "node_modules/fsevents": { @@ -1045,6 +1081,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/jsep/-/jsep-1.4.0.tgz", "integrity": "sha512-B7qPcEVE3NVkmSJbaYxvv4cHkVW7DQsZz13pUMrfS8z8Q/BuShN+gcTXrUlPiGqM2/t/EEaI030bpxMqY8gMlw==", + "license": "MIT", "engines": { "node": ">= 10.16.0" } @@ -1053,6 +1090,7 @@ "version": "10.1.0", "resolved": "https://registry.npmjs.org/jsonpath-plus/-/jsonpath-plus-10.1.0.tgz", "integrity": "sha512-gHfV1IYqH8uJHYVTs8BJX1XKy2/rR93+f8QQi0xhx95aCiXn1ettYAd5T+7FU6wfqyDoX/wy0pm/fL3jOKJ9Lg==", + "license": "MIT", "dependencies": { "@jsep-plugin/assignment": "^1.2.1", "@jsep-plugin/regex": "^1.0.3", @@ -1069,23 +1107,27 @@ "node_modules/lil-gui": { "version": "0.20.0", "resolved": "https://registry.npmjs.org/lil-gui/-/lil-gui-0.20.0.tgz", - "integrity": "sha512-k7Ipr0ztqslMA2XvM5z5ZaWhxQtnEOwJBfI/hmSuRh6q4iMG9L0boqqrnZSzBR1jzyJ28OMl47l65ILzRe1TdA==" + "integrity": "sha512-k7Ipr0ztqslMA2XvM5z5ZaWhxQtnEOwJBfI/hmSuRh6q4iMG9L0boqqrnZSzBR1jzyJ28OMl47l65ILzRe1TdA==", + "license": "MIT" }, "node_modules/manifold-3d": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/manifold-3d/-/manifold-3d-3.0.0.tgz", - "integrity": "sha512-6XxRf5LH4s7WIlRrvtzLMg+CHio5TznIE0w0PU/Ad8IzD36QLjb64QdSeQp9ISrk4tGtIqVAycevpPe1ExGTKg==" + "integrity": "sha512-6XxRf5LH4s7WIlRrvtzLMg+CHio5TznIE0w0PU/Ad8IzD36QLjb64QdSeQp9ISrk4tGtIqVAycevpPe1ExGTKg==", + "license": "Apache-2.0" }, "node_modules/meshoptimizer": { "version": "0.18.1", "resolved": "https://registry.npmjs.org/meshoptimizer/-/meshoptimizer-0.18.1.tgz", "integrity": "sha512-ZhoIoL7TNV4s5B6+rx5mC//fw8/POGyNxS/DZyCJeiZ12ScLfVwRE/GfsxwiTkMYYD5DmK2/JXnEVXqL4rF+Sw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/nan": { "version": "2.22.2", "resolved": "https://registry.npmjs.org/nan/-/nan-2.22.2.tgz", "integrity": "sha512-DANghxFkS1plDdRsX0X9pm0Z6SJNN6gBdtXfanwoZ8hooC5gosGFSBGRYHUVPz1asKA/kMRqDRdHrluZ61SpBQ==", + "license": "MIT", "optional": true }, "node_modules/nanoid": { @@ -1110,6 +1152,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/onml/-/onml-1.2.0.tgz", "integrity": "sha512-olqYAg18XoHAhm7tK9DdBCOVdts70DGmMgCNLOWyqZokht2utgGSKBB4JHi6pBZpmioAhcYlxK+91L3tsrz+GA==", + "license": "MIT", "dependencies": { "sax": "^1.2.1" } @@ -1161,9 +1204,9 @@ } }, "node_modules/rollup": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.41.0.tgz", - "integrity": "sha512-HqMFpUbWlf/tvcxBFNKnJyzc7Lk+XO3FGc3pbNBLqEbOz0gPLRgcrlS3UF4MfUrVlstOaP/q0kM6GVvi+LrLRg==", + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.40.1.tgz", + "integrity": "sha512-C5VvvgCCyfyotVITIAv+4efVytl5F7wt+/I2i9q9GZcEXW9BP52YYOXC58igUi+LFZVHukErIIqQSWwv/M3WRw==", "dev": true, "dependencies": { "@types/estree": "1.0.7" @@ -1176,26 +1219,26 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.41.0", - "@rollup/rollup-android-arm64": "4.41.0", - "@rollup/rollup-darwin-arm64": "4.41.0", - "@rollup/rollup-darwin-x64": "4.41.0", - "@rollup/rollup-freebsd-arm64": "4.41.0", - "@rollup/rollup-freebsd-x64": "4.41.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.41.0", - "@rollup/rollup-linux-arm-musleabihf": "4.41.0", - "@rollup/rollup-linux-arm64-gnu": "4.41.0", - "@rollup/rollup-linux-arm64-musl": "4.41.0", - "@rollup/rollup-linux-loongarch64-gnu": "4.41.0", - "@rollup/rollup-linux-powerpc64le-gnu": "4.41.0", - "@rollup/rollup-linux-riscv64-gnu": "4.41.0", - "@rollup/rollup-linux-riscv64-musl": "4.41.0", - "@rollup/rollup-linux-s390x-gnu": "4.41.0", - "@rollup/rollup-linux-x64-gnu": "4.41.0", - "@rollup/rollup-linux-x64-musl": "4.41.0", - "@rollup/rollup-win32-arm64-msvc": "4.41.0", - "@rollup/rollup-win32-ia32-msvc": "4.41.0", - "@rollup/rollup-win32-x64-msvc": "4.41.0", + "@rollup/rollup-android-arm-eabi": "4.40.1", + "@rollup/rollup-android-arm64": "4.40.1", + "@rollup/rollup-darwin-arm64": "4.40.1", + "@rollup/rollup-darwin-x64": "4.40.1", + "@rollup/rollup-freebsd-arm64": "4.40.1", + "@rollup/rollup-freebsd-x64": "4.40.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.40.1", + "@rollup/rollup-linux-arm-musleabihf": "4.40.1", + "@rollup/rollup-linux-arm64-gnu": "4.40.1", + "@rollup/rollup-linux-arm64-musl": "4.40.1", + "@rollup/rollup-linux-loongarch64-gnu": "4.40.1", + "@rollup/rollup-linux-powerpc64le-gnu": "4.40.1", + "@rollup/rollup-linux-riscv64-gnu": "4.40.1", + "@rollup/rollup-linux-riscv64-musl": "4.40.1", + "@rollup/rollup-linux-s390x-gnu": "4.40.1", + "@rollup/rollup-linux-x64-gnu": "4.40.1", + "@rollup/rollup-linux-x64-musl": "4.40.1", + "@rollup/rollup-win32-arm64-msvc": "4.40.1", + "@rollup/rollup-win32-ia32-msvc": "4.40.1", + "@rollup/rollup-win32-x64-msvc": "4.40.1", "fsevents": "~2.3.2" } }, @@ -1203,6 +1246,7 @@ "version": "7.5.5", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.5.tgz", "integrity": "sha512-sy+H0pQofO95VDmFLzyaw9xNJU4KTRSwQIGM6+iG3SypAtCiLDzpeG8sJrNCWn2Up9km+KhkvTdbkrdy+yzZdw==", + "license": "Apache-2.0", "dependencies": { "tslib": "^2.1.0" } @@ -1210,7 +1254,8 @@ "node_modules/sax": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", - "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==" + "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==", + "license": "ISC" }, "node_modules/source-map-js": { "version": "1.2.1", @@ -1240,7 +1285,8 @@ "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" }, "node_modules/typescript": { "version": "5.8.3", @@ -1259,14 +1305,15 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/verb-nurbs-web/-/verb-nurbs-web-2.1.3.tgz", "integrity": "sha512-2PvI2bx7dn0r3kWtk+JuDIDZ+p7I5Piu8y6/ZNhUVpilOyHKK1nNzLHtgown+dFOmBnKnuAKIMh1xn/5kzrxZA==", + "license": "MIT", "optionalDependencies": { "webworker-threads": "^0.7.12" } }, "node_modules/vite": { - "version": "6.3.5", - "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz", - "integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==", + "version": "6.3.4", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.4.tgz", + "integrity": "sha512-BiReIiMS2fyFqbqNT/Qqt4CVITDU9M9vE+DKcVAsB+ZV0wvTKd+3hMbkpxz1b+NmEDMegpVbisKiAZOnvO92Sw==", "dev": true, "dependencies": { "esbuild": "^0.25.0", @@ -1342,6 +1389,7 @@ "resolved": "https://registry.npmjs.org/webworker-threads/-/webworker-threads-0.7.17.tgz", "integrity": "sha512-Y2w2aXBbDLk9IzTEb9u+MsODC3s4YlGI7g4h0t+1OAwIO8yBI9rQL35ZYlyayiCuWu1dZMH/P7kGU8OwW7YsyA==", "hasInstallScript": true, + "license": "(MIT AND Apache-2.0)", "optional": true, "dependencies": { "bindings": "^1.3.0", @@ -1351,5 +1399,824 @@ "node": ">= 0.10.16" } } + }, + "dependencies": { + "@babylonjs/core": { + "version": "8.9.1", + "resolved": "https://registry.npmjs.org/@babylonjs/core/-/core-8.9.1.tgz", + "integrity": "sha512-YJvsQgjEtBIKDJXCi+6rhPH5UJ46QbaMknO5fQGg8tT2PI5L6D+vfrhdZc1YNnzDrOmLkrkXF/Uy2CGdXFdT9Q==" + }, + "@babylonjs/gui": { + "version": "8.9.1", + "resolved": "https://registry.npmjs.org/@babylonjs/gui/-/gui-8.9.1.tgz", + "integrity": "sha512-kYxPJ8C3HlNYrsKn3fPXJhQ8/BFUxMksBSNKQD+AsduEFWsMSlViYPdcMFh3oGpXEFZsqefoBoQe9xwN9L7brw==", + "requires": {} + }, + "@babylonjs/havok": { + "version": "1.3.10", + "resolved": "https://registry.npmjs.org/@babylonjs/havok/-/havok-1.3.10.tgz", + "integrity": "sha512-ddF0LPBVmg+rmPaMmwTPA9FcHyUnrSsQqFoBbYbN51WMhEJQ+7gRFW3J5lML6lN9M/fbknh6bh1ZirZ2bU2B/w==", + "requires": { + "@types/emscripten": "^1.39.6" + } + }, + "@babylonjs/loaders": { + "version": "8.9.1", + "resolved": "https://registry.npmjs.org/@babylonjs/loaders/-/loaders-8.9.1.tgz", + "integrity": "sha512-8UolyusbjHoVVD2nNrqMMNS0a6OIiGrxPyzs6LYqCRFuXKXNhnFIPYCNU3WEBeD5Uc3+UQXgSaQpZudtjflFMw==", + "requires": {} + }, + "@babylonjs/materials": { + "version": "8.9.1", + "resolved": "https://registry.npmjs.org/@babylonjs/materials/-/materials-8.9.1.tgz", + "integrity": "sha512-/Ey/Kkb9JcqM1eJ7HpOcvMhCbE2CAPRJRBhTCe6jUQ08eG/nuOJHs5SRUBdP4X4DRxgDQWY0owFP2nLLWQKM6A==", + "requires": {} + }, + "@babylonjs/serializers": { + "version": "8.9.1", + "resolved": "https://registry.npmjs.org/@babylonjs/serializers/-/serializers-8.9.1.tgz", + "integrity": "sha512-iGsizPwkQp00PaBzZing+5/CBR/x2yCkGu7GsOx2uFfoutihtn8zy+u51rarE2O6TO2sNjxp/KxCMng48c8KWA==", + "requires": {} + }, + "@bitbybit-dev/babylonjs": { + "version": "0.20.4", + "resolved": "https://registry.npmjs.org/@bitbybit-dev/babylonjs/-/babylonjs-0.20.4.tgz", + "integrity": "sha512-tn+1VYQgz+6c2i16HpkIgWnIIRdnUCQKFdA701QGcKB59zJ67rU7Y8TIVTSVgPwJ9mJLpg1Co3bCVYEAyGCYXw==", + "requires": { + "@babylonjs/core": "8.9.1", + "@babylonjs/gui": "8.9.1", + "@babylonjs/havok": "1.3.10", + "@babylonjs/loaders": "8.9.1", + "@babylonjs/materials": "8.9.1", + "@babylonjs/serializers": "8.9.1", + "@bitbybit-dev/core": "0.20.4", + "earcut": "2.2.3" + } + }, + "@bitbybit-dev/base": { + "version": "0.20.4", + "resolved": "https://registry.npmjs.org/@bitbybit-dev/base/-/base-0.20.4.tgz", + "integrity": "sha512-yMsOkUFrm9JIGC3Bs49bu1I/gqwQNK8nVO3XgesOpzZvVQOF5OTxCheiQnrqiUw9DiiPuKw1T0gXBMwThzwdOw==" + }, + "@bitbybit-dev/core": { + "version": "0.20.4", + "resolved": "https://registry.npmjs.org/@bitbybit-dev/core/-/core-0.20.4.tgz", + "integrity": "sha512-T2hOHzvI+ikNxQRvhDyk/TeMCBhjZPY+wLmRSbYHiWnNGP5+3GCesZyb672XfEwPIWRH2kBS4vyp9R9fRnJujQ==", + "requires": { + "@bitbybit-dev/base": "0.20.4", + "@bitbybit-dev/jscad-worker": "0.20.4", + "@bitbybit-dev/manifold-worker": "0.20.4", + "@bitbybit-dev/occt-worker": "0.20.4", + "jsonpath-plus": "10.1.0", + "rxjs": "7.5.5", + "verb-nurbs-web": "2.1.3" + } + }, + "@bitbybit-dev/jscad": { + "version": "0.20.4", + "resolved": "https://registry.npmjs.org/@bitbybit-dev/jscad/-/jscad-0.20.4.tgz", + "integrity": "sha512-e7/7Ag796rwn58H6Nu0lzhDkim+rJTqMWCqFZquNswoX2qqZXCv8azyOFE2LqfTvyIsEeJr/VEWIy2nvmtJnmg==", + "requires": { + "@bitbybit-dev/base": "0.20.4", + "@jscad/3mf-serializer": "2.1.12", + "@jscad/dxf-serializer": "2.1.18", + "@jscad/io-utils": "2.0.28", + "@jscad/modeling": "2.12.3", + "@jscad/stl-serializer": "2.1.18" + } + }, + "@bitbybit-dev/jscad-worker": { + "version": "0.20.4", + "resolved": "https://registry.npmjs.org/@bitbybit-dev/jscad-worker/-/jscad-worker-0.20.4.tgz", + "integrity": "sha512-DsjL2YO6urR8B/8LKYRrk4q9hAJE8oB+e5m+LDDBXbl7Vl0CHdC5ogPm6w07RcAHdSbMJouf2Ow7nGP/oOcjEg==", + "requires": { + "@bitbybit-dev/jscad": "0.20.4", + "rxjs": "7.5.5" + } + }, + "@bitbybit-dev/manifold": { + "version": "0.20.4", + "resolved": "https://registry.npmjs.org/@bitbybit-dev/manifold/-/manifold-0.20.4.tgz", + "integrity": "sha512-rEGO8wOd/RUWPIRWdyE70w79JXhQ1iV6mACBuOH8/UD7+vf9wkk3KLWAYCzVPJP1nvx4+/SKCvU7e1JxEzq0Qw==", + "requires": { + "manifold-3d": "3.0.0" + } + }, + "@bitbybit-dev/manifold-worker": { + "version": "0.20.4", + "resolved": "https://registry.npmjs.org/@bitbybit-dev/manifold-worker/-/manifold-worker-0.20.4.tgz", + "integrity": "sha512-mwU87fg8M3p472dn/RiuveiPtq/IuOWCcoG0uismEE2g+rnciMrCSUSkXMkfXDCk9l0ZqoVfYg+dHVx0KBHBUg==", + "requires": { + "@bitbybit-dev/manifold": "0.20.4", + "rxjs": "7.5.5" + } + }, + "@bitbybit-dev/occt": { + "version": "0.20.4", + "resolved": "https://registry.npmjs.org/@bitbybit-dev/occt/-/occt-0.20.4.tgz", + "integrity": "sha512-Lxx4wsToS3EIiS2L3KjUh6Jpgvxsyxbh2Jt4raWhIbD9PSy1zRfMww9K7xFlawSMgq12WN1a0lV8ydKs1f5/zw==", + "requires": { + "@bitbybit-dev/base": "0.20.4" + } + }, + "@bitbybit-dev/occt-worker": { + "version": "0.20.4", + "resolved": "https://registry.npmjs.org/@bitbybit-dev/occt-worker/-/occt-worker-0.20.4.tgz", + "integrity": "sha512-R5fiGteBSitv89Pz3XVgs+Vv0c1uH477oihkw1EUWLDTa7ypiXOohpjlKYFd/qAy3QCe8GEF3jDT+TK3dsQ+FA==", + "requires": { + "@bitbybit-dev/occt": "0.20.4", + "rxjs": "7.5.5" + } + }, + "@dimforge/rapier3d-compat": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@dimforge/rapier3d-compat/-/rapier3d-compat-0.12.0.tgz", + "integrity": "sha512-uekIGetywIgopfD97oDL5PfeezkFpNhwlzlaEYNOA0N6ghdsOvh/HYjSMek5Q2O1PYvRSDFcqFVJl4r4ZBwOow==", + "dev": true + }, + "@esbuild/aix-ppc64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.3.tgz", + "integrity": "sha512-W8bFfPA8DowP8l//sxjJLSLkD8iEjMc7cBVyP+u4cEv9sM7mdUCkgsj+t0n/BWPFtv7WWCN5Yzj0N6FJNUUqBQ==", + "dev": true, + "optional": true + }, + "@esbuild/android-arm": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.3.tgz", + "integrity": "sha512-PuwVXbnP87Tcff5I9ngV0lmiSu40xw1At6i3GsU77U7cjDDB4s0X2cyFuBiDa1SBk9DnvWwnGvVaGBqoFWPb7A==", + "dev": true, + "optional": true + }, + "@esbuild/android-arm64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.3.tgz", + "integrity": "sha512-XelR6MzjlZuBM4f5z2IQHK6LkK34Cvv6Rj2EntER3lwCBFdg6h2lKbtRjpTTsdEjD/WSe1q8UyPBXP1x3i/wYQ==", + "dev": true, + "optional": true + }, + "@esbuild/android-x64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.3.tgz", + "integrity": "sha512-ogtTpYHT/g1GWS/zKM0cc/tIebFjm1F9Aw1boQ2Y0eUQ+J89d0jFY//s9ei9jVIlkYi8AfOjiixcLJSGNSOAdQ==", + "dev": true, + "optional": true + }, + "@esbuild/darwin-arm64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.3.tgz", + "integrity": "sha512-eESK5yfPNTqpAmDfFWNsOhmIOaQA59tAcF/EfYvo5/QWQCzXn5iUSOnqt3ra3UdzBv073ykTtmeLJZGt3HhA+w==", + "dev": true, + "optional": true + }, + "@esbuild/darwin-x64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.3.tgz", + "integrity": "sha512-Kd8glo7sIZtwOLcPbW0yLpKmBNWMANZhrC1r6K++uDR2zyzb6AeOYtI6udbtabmQpFaxJ8uduXMAo1gs5ozz8A==", + "dev": true, + "optional": true + }, + "@esbuild/freebsd-arm64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.3.tgz", + "integrity": "sha512-EJiyS70BYybOBpJth3M0KLOus0n+RRMKTYzhYhFeMwp7e/RaajXvP+BWlmEXNk6uk+KAu46j/kaQzr6au+JcIw==", + "dev": true, + "optional": true + }, + "@esbuild/freebsd-x64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.3.tgz", + "integrity": "sha512-Q+wSjaLpGxYf7zC0kL0nDlhsfuFkoN+EXrx2KSB33RhinWzejOd6AvgmP5JbkgXKmjhmpfgKZq24pneodYqE8Q==", + "dev": true, + "optional": true + }, + "@esbuild/linux-arm": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.3.tgz", + "integrity": "sha512-dUOVmAUzuHy2ZOKIHIKHCm58HKzFqd+puLaS424h6I85GlSDRZIA5ycBixb3mFgM0Jdh+ZOSB6KptX30DD8YOQ==", + "dev": true, + "optional": true + }, + "@esbuild/linux-arm64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.3.tgz", + "integrity": "sha512-xCUgnNYhRD5bb1C1nqrDV1PfkwgbswTTBRbAd8aH5PhYzikdf/ddtsYyMXFfGSsb/6t6QaPSzxtbfAZr9uox4A==", + "dev": true, + "optional": true + }, + "@esbuild/linux-ia32": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.3.tgz", + "integrity": "sha512-yplPOpczHOO4jTYKmuYuANI3WhvIPSVANGcNUeMlxH4twz/TeXuzEP41tGKNGWJjuMhotpGabeFYGAOU2ummBw==", + "dev": true, + "optional": true + }, + "@esbuild/linux-loong64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.3.tgz", + "integrity": "sha512-P4BLP5/fjyihmXCELRGrLd793q/lBtKMQl8ARGpDxgzgIKJDRJ/u4r1A/HgpBpKpKZelGct2PGI4T+axcedf6g==", + "dev": true, + "optional": true + }, + "@esbuild/linux-mips64el": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.3.tgz", + "integrity": "sha512-eRAOV2ODpu6P5divMEMa26RRqb2yUoYsuQQOuFUexUoQndm4MdpXXDBbUoKIc0iPa4aCO7gIhtnYomkn2x+bag==", + "dev": true, + "optional": true + }, + "@esbuild/linux-ppc64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.3.tgz", + "integrity": "sha512-ZC4jV2p7VbzTlnl8nZKLcBkfzIf4Yad1SJM4ZMKYnJqZFD4rTI+pBG65u8ev4jk3/MPwY9DvGn50wi3uhdaghg==", + "dev": true, + "optional": true + }, + "@esbuild/linux-riscv64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.3.tgz", + "integrity": "sha512-LDDODcFzNtECTrUUbVCs6j9/bDVqy7DDRsuIXJg6so+mFksgwG7ZVnTruYi5V+z3eE5y+BJZw7VvUadkbfg7QA==", + "dev": true, + "optional": true + }, + "@esbuild/linux-s390x": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.3.tgz", + "integrity": "sha512-s+w/NOY2k0yC2p9SLen+ymflgcpRkvwwa02fqmAwhBRI3SC12uiS10edHHXlVWwfAagYSY5UpmT/zISXPMW3tQ==", + "dev": true, + "optional": true + }, + "@esbuild/linux-x64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.3.tgz", + "integrity": "sha512-nQHDz4pXjSDC6UfOE1Fw9Q8d6GCAd9KdvMZpfVGWSJztYCarRgSDfOVBY5xwhQXseiyxapkiSJi/5/ja8mRFFA==", + "dev": true, + "optional": true + }, + "@esbuild/netbsd-arm64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.3.tgz", + "integrity": "sha512-1QaLtOWq0mzK6tzzp0jRN3eccmN3hezey7mhLnzC6oNlJoUJz4nym5ZD7mDnS/LZQgkrhEbEiTn515lPeLpgWA==", + "dev": true, + "optional": true + }, + "@esbuild/netbsd-x64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.3.tgz", + "integrity": "sha512-i5Hm68HXHdgv8wkrt+10Bc50zM0/eonPb/a/OFVfB6Qvpiirco5gBA5bz7S2SHuU+Y4LWn/zehzNX14Sp4r27g==", + "dev": true, + "optional": true + }, + "@esbuild/openbsd-arm64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.3.tgz", + "integrity": "sha512-zGAVApJEYTbOC6H/3QBr2mq3upG/LBEXr85/pTtKiv2IXcgKV0RT0QA/hSXZqSvLEpXeIxah7LczB4lkiYhTAQ==", + "dev": true, + "optional": true + }, + "@esbuild/openbsd-x64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.3.tgz", + "integrity": "sha512-fpqctI45NnCIDKBH5AXQBsD0NDPbEFczK98hk/aa6HJxbl+UtLkJV2+Bvy5hLSLk3LHmqt0NTkKNso1A9y1a4w==", + "dev": true, + "optional": true + }, + "@esbuild/sunos-x64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.3.tgz", + "integrity": "sha512-ROJhm7d8bk9dMCUZjkS8fgzsPAZEjtRJqCAmVgB0gMrvG7hfmPmz9k1rwO4jSiblFjYmNvbECL9uhaPzONMfgA==", + "dev": true, + "optional": true + }, + "@esbuild/win32-arm64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.3.tgz", + "integrity": "sha512-YWcow8peiHpNBiIXHwaswPnAXLsLVygFwCB3A7Bh5jRkIBFWHGmNQ48AlX4xDvQNoMZlPYzjVOQDYEzWCqufMQ==", + "dev": true, + "optional": true + }, + "@esbuild/win32-ia32": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.3.tgz", + "integrity": "sha512-qspTZOIGoXVS4DpNqUYUs9UxVb04khS1Degaw/MnfMe7goQ3lTfQ13Vw4qY/Nj0979BGvMRpAYbs/BAxEvU8ew==", + "dev": true, + "optional": true + }, + "@esbuild/win32-x64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.3.tgz", + "integrity": "sha512-ICgUR+kPimx0vvRzf+N/7L7tVSQeE3BYY+NhHRHXS1kBuPO7z2+7ea2HbhDyZdTephgvNvKrlDDKUexuCVBVvg==", + "dev": true, + "optional": true + }, + "@jscad/3mf-serializer": { + "version": "2.1.12", + "resolved": "https://registry.npmjs.org/@jscad/3mf-serializer/-/3mf-serializer-2.1.12.tgz", + "integrity": "sha512-+rxAIKIHCpaplupwwsdXtG1IdimPXFFB45nrjy6gdFHi36bEQW6y/RQD/ngenRiKnYSxu7/M0LatHcjve8z64A==", + "requires": { + "@jscad/array-utils": "2.1.4", + "@jscad/modeling": "2.12.3", + "fflate": "0.7.3", + "onml": "1.2.0" + } + }, + "@jscad/array-utils": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@jscad/array-utils/-/array-utils-2.1.4.tgz", + "integrity": "sha512-c31r4zSKsE+4Xfwk2V8monDA0hx5G89QGzaakWVUvuGNowYS9WSsYCwHiTIXodjR+HEnDu4okQ7k/whmP0Ne2g==" + }, + "@jscad/dxf-serializer": { + "version": "2.1.18", + "resolved": "https://registry.npmjs.org/@jscad/dxf-serializer/-/dxf-serializer-2.1.18.tgz", + "integrity": "sha512-T5Qe2jbEphcWAk7GaOY8PCMD4DPhTm6gWk/MPJCExphhnUwJqcU/1RiMb5hiD+N6hHzmlxD59I8QTjlp9LbLSA==", + "requires": { + "@jscad/array-utils": "2.1.4", + "@jscad/modeling": "2.12.3" + } + }, + "@jscad/io-utils": { + "version": "2.0.28", + "resolved": "https://registry.npmjs.org/@jscad/io-utils/-/io-utils-2.0.28.tgz", + "integrity": "sha512-spXh37wAgmwjKztoH/HANLgImcqRHX5+H/cRIxPfpqDIWvu7I5bRg2ZTwh25SYlKIzxPk4qX5Nu7Ax5+Kg+QXQ==" + }, + "@jscad/modeling": { + "version": "2.12.3", + "resolved": "https://registry.npmjs.org/@jscad/modeling/-/modeling-2.12.3.tgz", + "integrity": "sha512-DnAacXq3zhlYWIixGlFD7RMpgZAMuCaMZNQov0NaoFfs2GaBuTC5eqkqKcEVbhEerBmTllbjjF5IXjJMt9jcOA==" + }, + "@jscad/stl-serializer": { + "version": "2.1.18", + "resolved": "https://registry.npmjs.org/@jscad/stl-serializer/-/stl-serializer-2.1.18.tgz", + "integrity": "sha512-pz++TRjHI7jBPnnxQUi4B/uYUG3yCDsKlw8+xL2kumwjb+auc6Ng6Rnr/GqUTkgHrnGut08wg/8AekyWjvBwYg==", + "requires": { + "@jscad/array-utils": "2.1.4", + "@jscad/modeling": "2.12.3" + } + }, + "@jsep-plugin/assignment": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@jsep-plugin/assignment/-/assignment-1.3.0.tgz", + "integrity": "sha512-VVgV+CXrhbMI3aSusQyclHkenWSAm95WaiKrMxRFam3JSUiIaQjoMIw2sEs/OX4XifnqeQUN4DYbJjlA8EfktQ==", + "requires": {} + }, + "@jsep-plugin/regex": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@jsep-plugin/regex/-/regex-1.0.4.tgz", + "integrity": "sha512-q7qL4Mgjs1vByCaTnDFcBnV9HS7GVPJX5vyVoCgZHNSC9rjwIlmbXG5sUuorR5ndfHAIlJ8pVStxvjXHbNvtUg==", + "requires": {} + }, + "@rollup/rollup-android-arm-eabi": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.40.1.tgz", + "integrity": "sha512-kxz0YeeCrRUHz3zyqvd7n+TVRlNyTifBsmnmNPtk3hQURUyG9eAB+usz6DAwagMusjx/zb3AjvDUvhFGDAexGw==", + "dev": true, + "optional": true + }, + "@rollup/rollup-android-arm64": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.40.1.tgz", + "integrity": "sha512-PPkxTOisoNC6TpnDKatjKkjRMsdaWIhyuMkA4UsBXT9WEZY4uHezBTjs6Vl4PbqQQeu6oION1w2voYZv9yquCw==", + "dev": true, + "optional": true + }, + "@rollup/rollup-darwin-arm64": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.40.1.tgz", + "integrity": "sha512-VWXGISWFY18v/0JyNUy4A46KCFCb9NVsH+1100XP31lud+TzlezBbz24CYzbnA4x6w4hx+NYCXDfnvDVO6lcAA==", + "dev": true, + "optional": true + }, + "@rollup/rollup-darwin-x64": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.40.1.tgz", + "integrity": "sha512-nIwkXafAI1/QCS7pxSpv/ZtFW6TXcNUEHAIA9EIyw5OzxJZQ1YDrX+CL6JAIQgZ33CInl1R6mHet9Y/UZTg2Bw==", + "dev": true, + "optional": true + }, + "@rollup/rollup-freebsd-arm64": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.40.1.tgz", + "integrity": "sha512-BdrLJ2mHTrIYdaS2I99mriyJfGGenSaP+UwGi1kB9BLOCu9SR8ZpbkmmalKIALnRw24kM7qCN0IOm6L0S44iWw==", + "dev": true, + "optional": true + }, + "@rollup/rollup-freebsd-x64": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.40.1.tgz", + "integrity": "sha512-VXeo/puqvCG8JBPNZXZf5Dqq7BzElNJzHRRw3vjBE27WujdzuOPecDPc/+1DcdcTptNBep3861jNq0mYkT8Z6Q==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.40.1.tgz", + "integrity": "sha512-ehSKrewwsESPt1TgSE/na9nIhWCosfGSFqv7vwEtjyAqZcvbGIg4JAcV7ZEh2tfj/IlfBeZjgOXm35iOOjadcg==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-arm-musleabihf": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.40.1.tgz", + "integrity": "sha512-m39iO/aaurh5FVIu/F4/Zsl8xppd76S4qoID8E+dSRQvTyZTOI2gVk3T4oqzfq1PtcvOfAVlwLMK3KRQMaR8lg==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-arm64-gnu": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.40.1.tgz", + "integrity": "sha512-Y+GHnGaku4aVLSgrT0uWe2o2Rq8te9hi+MwqGF9r9ORgXhmHK5Q71N757u0F8yU1OIwUIFy6YiJtKjtyktk5hg==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-arm64-musl": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.40.1.tgz", + "integrity": "sha512-jEwjn3jCA+tQGswK3aEWcD09/7M5wGwc6+flhva7dsQNRZZTe30vkalgIzV4tjkopsTS9Jd7Y1Bsj6a4lzz8gQ==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.40.1.tgz", + "integrity": "sha512-ySyWikVhNzv+BV/IDCsrraOAZ3UaC8SZB67FZlqVwXwnFhPihOso9rPOxzZbjp81suB1O2Topw+6Ug3JNegejQ==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.40.1.tgz", + "integrity": "sha512-BvvA64QxZlh7WZWqDPPdt0GH4bznuL6uOO1pmgPnnv86rpUpc8ZxgZwcEgXvo02GRIZX1hQ0j0pAnhwkhwPqWg==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-riscv64-gnu": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.40.1.tgz", + "integrity": "sha512-EQSP+8+1VuSulm9RKSMKitTav89fKbHymTf25n5+Yr6gAPZxYWpj3DzAsQqoaHAk9YX2lwEyAf9S4W8F4l3VBQ==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-riscv64-musl": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.40.1.tgz", + "integrity": "sha512-n/vQ4xRZXKuIpqukkMXZt9RWdl+2zgGNx7Uda8NtmLJ06NL8jiHxUawbwC+hdSq1rrw/9CghCpEONor+l1e2gA==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-s390x-gnu": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.40.1.tgz", + "integrity": "sha512-h8d28xzYb98fMQKUz0w2fMc1XuGzLLjdyxVIbhbil4ELfk5/orZlSTpF/xdI9C8K0I8lCkq+1En2RJsawZekkg==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-x64-gnu": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.40.1.tgz", + "integrity": "sha512-XiK5z70PEFEFqcNj3/zRSz/qX4bp4QIraTy9QjwJAb/Z8GM7kVUsD0Uk8maIPeTyPCP03ChdI+VVmJriKYbRHQ==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-x64-musl": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.40.1.tgz", + "integrity": "sha512-2BRORitq5rQ4Da9blVovzNCMaUlyKrzMSvkVR0D4qPuOy/+pMCrh1d7o01RATwVy+6Fa1WBw+da7QPeLWU/1mQ==", + "dev": true, + "optional": true + }, + "@rollup/rollup-win32-arm64-msvc": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.40.1.tgz", + "integrity": "sha512-b2bcNm9Kbde03H+q+Jjw9tSfhYkzrDUf2d5MAd1bOJuVplXvFhWz7tRtWvD8/ORZi7qSCy0idW6tf2HgxSXQSg==", + "dev": true, + "optional": true + }, + "@rollup/rollup-win32-ia32-msvc": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.40.1.tgz", + "integrity": "sha512-DfcogW8N7Zg7llVEfpqWMZcaErKfsj9VvmfSyRjCyo4BI3wPEfrzTtJkZG6gKP/Z92wFm6rz2aDO7/JfiR/whA==", + "dev": true, + "optional": true + }, + "@rollup/rollup-win32-x64-msvc": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.40.1.tgz", + "integrity": "sha512-ECyOuDeH3C1I8jH2MK1RtBJW+YPMvSfT0a5NN0nHfQYnDSJ6tUiZH3gzwVP5/Kfh/+Tt7tpWVF9LXNTnhTJ3kA==", + "dev": true, + "optional": true + }, + "@tweenjs/tween.js": { + "version": "23.1.3", + "resolved": "https://registry.npmjs.org/@tweenjs/tween.js/-/tween.js-23.1.3.tgz", + "integrity": "sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA==", + "dev": true + }, + "@types/emscripten": { + "version": "1.40.1", + "resolved": "https://registry.npmjs.org/@types/emscripten/-/emscripten-1.40.1.tgz", + "integrity": "sha512-sr53lnYkQNhjHNN0oJDdUm5564biioI5DuOpycufDVK7D3y+GR3oUswe2rlwY1nPNyusHbrJ9WoTyIHl4/Bpwg==" + }, + "@types/estree": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", + "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==", + "dev": true + }, + "@types/stats.js": { + "version": "0.17.3", + "resolved": "https://registry.npmjs.org/@types/stats.js/-/stats.js-0.17.3.tgz", + "integrity": "sha512-pXNfAD3KHOdif9EQXZ9deK82HVNaXP5ZIF5RP2QG6OQFNTaY2YIetfrE9t528vEreGQvEPRDDc8muaoYeK0SxQ==", + "dev": true + }, + "@types/three": { + "version": "0.176.0", + "resolved": "https://registry.npmjs.org/@types/three/-/three-0.176.0.tgz", + "integrity": "sha512-FwfPXxCqOtP7EdYMagCFePNKoG1AGBDUEVKtluv2BTVRpSt7b+X27xNsirPCTCqY1pGYsPUzaM3jgWP7dXSxlw==", + "dev": true, + "requires": { + "@dimforge/rapier3d-compat": "^0.12.0", + "@tweenjs/tween.js": "~23.1.3", + "@types/stats.js": "*", + "@types/webxr": "*", + "@webgpu/types": "*", + "fflate": "~0.8.2", + "meshoptimizer": "~0.18.1" + }, + "dependencies": { + "fflate": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz", + "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==", + "dev": true + } + } + }, + "@types/webxr": { + "version": "0.5.22", + "resolved": "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.22.tgz", + "integrity": "sha512-Vr6Stjv5jPRqH690f5I5GLjVk8GSsoQSYJ2FVd/3jJF7KaqfwPi3ehfBS96mlQ2kPCwZaX6U0rG2+NGHBKkA/A==", + "dev": true + }, + "@webgpu/types": { + "version": "0.1.60", + "resolved": "https://registry.npmjs.org/@webgpu/types/-/types-0.1.60.tgz", + "integrity": "sha512-8B/tdfRFKdrnejqmvq95ogp8tf52oZ51p3f4QD5m5Paey/qlX4Rhhy5Y8tgFMi7Ms70HzcMMw3EQjH/jdhTwlA==", + "dev": true + }, + "babylonjs-gltf2interface": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/babylonjs-gltf2interface/-/babylonjs-gltf2interface-8.10.0.tgz", + "integrity": "sha512-ExGp0TqBzX9ZnWryYSccNZJnFHAby4XHYhwvsCkOJy+3+uDb56x9Q7Ao1eGuncepzclSbzrxohuOhalPgm6dAw==", + "peer": true + }, + "bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "optional": true, + "requires": { + "file-uri-to-path": "1.0.0" + } + }, + "earcut": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/earcut/-/earcut-2.2.3.tgz", + "integrity": "sha512-iRDI1QeCQIhMCZk48DRDMVgQSSBDmbzzNhnxIo+pwx3swkfjMh6vh0nWLq1NdvGHLKH6wIrAM3vQWeTj6qeoug==" + }, + "esbuild": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.3.tgz", + "integrity": "sha512-qKA6Pvai73+M2FtftpNKRxJ78GIjmFXFxd/1DVBqGo/qNhLSfv+G12n9pNoWdytJC8U00TrViOwpjT0zgqQS8Q==", + "dev": true, + "requires": { + "@esbuild/aix-ppc64": "0.25.3", + "@esbuild/android-arm": "0.25.3", + "@esbuild/android-arm64": "0.25.3", + "@esbuild/android-x64": "0.25.3", + "@esbuild/darwin-arm64": "0.25.3", + "@esbuild/darwin-x64": "0.25.3", + "@esbuild/freebsd-arm64": "0.25.3", + "@esbuild/freebsd-x64": "0.25.3", + "@esbuild/linux-arm": "0.25.3", + "@esbuild/linux-arm64": "0.25.3", + "@esbuild/linux-ia32": "0.25.3", + "@esbuild/linux-loong64": "0.25.3", + "@esbuild/linux-mips64el": "0.25.3", + "@esbuild/linux-ppc64": "0.25.3", + "@esbuild/linux-riscv64": "0.25.3", + "@esbuild/linux-s390x": "0.25.3", + "@esbuild/linux-x64": "0.25.3", + "@esbuild/netbsd-arm64": "0.25.3", + "@esbuild/netbsd-x64": "0.25.3", + "@esbuild/openbsd-arm64": "0.25.3", + "@esbuild/openbsd-x64": "0.25.3", + "@esbuild/sunos-x64": "0.25.3", + "@esbuild/win32-arm64": "0.25.3", + "@esbuild/win32-ia32": "0.25.3", + "@esbuild/win32-x64": "0.25.3" + } + }, + "fdir": { + "version": "6.4.4", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.4.tgz", + "integrity": "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==", + "dev": true, + "requires": {} + }, + "fflate": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.7.3.tgz", + "integrity": "sha512-0Zz1jOzJWERhyhsimS54VTqOteCNwRtIlh8isdL0AXLo0g7xNTfTL7oWrkmCnPhZGocKIkWHBistBrrpoNH3aw==" + }, + "file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "optional": true + }, + "fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "optional": true + }, + "jsep": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/jsep/-/jsep-1.4.0.tgz", + "integrity": "sha512-B7qPcEVE3NVkmSJbaYxvv4cHkVW7DQsZz13pUMrfS8z8Q/BuShN+gcTXrUlPiGqM2/t/EEaI030bpxMqY8gMlw==" + }, + "jsonpath-plus": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/jsonpath-plus/-/jsonpath-plus-10.1.0.tgz", + "integrity": "sha512-gHfV1IYqH8uJHYVTs8BJX1XKy2/rR93+f8QQi0xhx95aCiXn1ettYAd5T+7FU6wfqyDoX/wy0pm/fL3jOKJ9Lg==", + "requires": { + "@jsep-plugin/assignment": "^1.2.1", + "@jsep-plugin/regex": "^1.0.3", + "jsep": "^1.3.9" + } + }, + "lil-gui": { + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/lil-gui/-/lil-gui-0.20.0.tgz", + "integrity": "sha512-k7Ipr0ztqslMA2XvM5z5ZaWhxQtnEOwJBfI/hmSuRh6q4iMG9L0boqqrnZSzBR1jzyJ28OMl47l65ILzRe1TdA==" + }, + "manifold-3d": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/manifold-3d/-/manifold-3d-3.0.0.tgz", + "integrity": "sha512-6XxRf5LH4s7WIlRrvtzLMg+CHio5TznIE0w0PU/Ad8IzD36QLjb64QdSeQp9ISrk4tGtIqVAycevpPe1ExGTKg==" + }, + "meshoptimizer": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/meshoptimizer/-/meshoptimizer-0.18.1.tgz", + "integrity": "sha512-ZhoIoL7TNV4s5B6+rx5mC//fw8/POGyNxS/DZyCJeiZ12ScLfVwRE/GfsxwiTkMYYD5DmK2/JXnEVXqL4rF+Sw==", + "dev": true + }, + "nan": { + "version": "2.22.2", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.22.2.tgz", + "integrity": "sha512-DANghxFkS1plDdRsX0X9pm0Z6SJNN6gBdtXfanwoZ8hooC5gosGFSBGRYHUVPz1asKA/kMRqDRdHrluZ61SpBQ==", + "optional": true + }, + "nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true + }, + "onml": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/onml/-/onml-1.2.0.tgz", + "integrity": "sha512-olqYAg18XoHAhm7tK9DdBCOVdts70DGmMgCNLOWyqZokht2utgGSKBB4JHi6pBZpmioAhcYlxK+91L3tsrz+GA==", + "requires": { + "sax": "^1.2.1" + } + }, + "picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true + }, + "picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true + }, + "postcss": { + "version": "8.5.3", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz", + "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==", + "dev": true, + "requires": { + "nanoid": "^3.3.8", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + } + }, + "rollup": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.40.1.tgz", + "integrity": "sha512-C5VvvgCCyfyotVITIAv+4efVytl5F7wt+/I2i9q9GZcEXW9BP52YYOXC58igUi+LFZVHukErIIqQSWwv/M3WRw==", + "dev": true, + "requires": { + "@rollup/rollup-android-arm-eabi": "4.40.1", + "@rollup/rollup-android-arm64": "4.40.1", + "@rollup/rollup-darwin-arm64": "4.40.1", + "@rollup/rollup-darwin-x64": "4.40.1", + "@rollup/rollup-freebsd-arm64": "4.40.1", + "@rollup/rollup-freebsd-x64": "4.40.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.40.1", + "@rollup/rollup-linux-arm-musleabihf": "4.40.1", + "@rollup/rollup-linux-arm64-gnu": "4.40.1", + "@rollup/rollup-linux-arm64-musl": "4.40.1", + "@rollup/rollup-linux-loongarch64-gnu": "4.40.1", + "@rollup/rollup-linux-powerpc64le-gnu": "4.40.1", + "@rollup/rollup-linux-riscv64-gnu": "4.40.1", + "@rollup/rollup-linux-riscv64-musl": "4.40.1", + "@rollup/rollup-linux-s390x-gnu": "4.40.1", + "@rollup/rollup-linux-x64-gnu": "4.40.1", + "@rollup/rollup-linux-x64-musl": "4.40.1", + "@rollup/rollup-win32-arm64-msvc": "4.40.1", + "@rollup/rollup-win32-ia32-msvc": "4.40.1", + "@rollup/rollup-win32-x64-msvc": "4.40.1", + "@types/estree": "1.0.7", + "fsevents": "~2.3.2" + } + }, + "rxjs": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.5.tgz", + "integrity": "sha512-sy+H0pQofO95VDmFLzyaw9xNJU4KTRSwQIGM6+iG3SypAtCiLDzpeG8sJrNCWn2Up9km+KhkvTdbkrdy+yzZdw==", + "requires": { + "tslib": "^2.1.0" + } + }, + "sax": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", + "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==" + }, + "source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true + }, + "tinyglobby": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.13.tgz", + "integrity": "sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==", + "dev": true, + "requires": { + "fdir": "^6.4.4", + "picomatch": "^4.0.2" + } + }, + "tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" + }, + "typescript": { + "version": "5.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", + "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", + "dev": true + }, + "verb-nurbs-web": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/verb-nurbs-web/-/verb-nurbs-web-2.1.3.tgz", + "integrity": "sha512-2PvI2bx7dn0r3kWtk+JuDIDZ+p7I5Piu8y6/ZNhUVpilOyHKK1nNzLHtgown+dFOmBnKnuAKIMh1xn/5kzrxZA==", + "requires": { + "webworker-threads": "^0.7.12" + } + }, + "vite": { + "version": "6.3.4", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.4.tgz", + "integrity": "sha512-BiReIiMS2fyFqbqNT/Qqt4CVITDU9M9vE+DKcVAsB+ZV0wvTKd+3hMbkpxz1b+NmEDMegpVbisKiAZOnvO92Sw==", + "dev": true, + "requires": { + "esbuild": "^0.25.0", + "fdir": "^6.4.4", + "fsevents": "~2.3.3", + "picomatch": "^4.0.2", + "postcss": "^8.5.3", + "rollup": "^4.34.9", + "tinyglobby": "^0.2.13" + } + }, + "webworker-threads": { + "version": "0.7.17", + "resolved": "https://registry.npmjs.org/webworker-threads/-/webworker-threads-0.7.17.tgz", + "integrity": "sha512-Y2w2aXBbDLk9IzTEb9u+MsODC3s4YlGI7g4h0t+1OAwIO8yBI9rQL35ZYlyayiCuWu1dZMH/P7kGU8OwW7YsyA==", + "optional": true, + "requires": { + "bindings": "^1.3.0", + "nan": "^2.11.0" + } + } } } diff --git a/examples/vite/babylonjs/hex-shell/src/helpers/create-gui.ts b/examples/vite/babylonjs/hex-shell/src/helpers/create-gui.ts new file mode 100644 index 00000000..ab17589f --- /dev/null +++ b/examples/vite/babylonjs/hex-shell/src/helpers/create-gui.ts @@ -0,0 +1,94 @@ +import GUI from "lil-gui"; +import type { Current, Model } from "../models"; +import { Color3, PBRMetallicRoughnessMaterial } from "@babylonjs/core"; + +export const createGui = ( + current: Current, + model: Model, + updateShape: (lod: boolean) => void +) => { + model.update = () => updateShape(true); + const gui = new GUI(); + current.gui = gui; + gui.$title.innerHTML = "Pattern"; + + gui + .add(model, "uHex", 1, 14, 1) + .name("Hexagons U") + .onFinishChange((value: number) => { + model.uHex = value; + updateShape(false); + }); + + gui + .add(model, "vHex", 8, 36, 2) + .name("Hexagons V") + .onFinishChange((value: number) => { + model.vHex = value; + updateShape(false); + }); + + gui + .add(model, "height", 15, 25, 1) + .name("Height") + .onFinishChange((value: number) => { + model.height = value; + updateShape(false); + }); + + gui + .add(model, "ellipse2RotX", 0, 15, 0.1) + .name("Angle Guide") + .onFinishChange((value: number) => { + model.ellipse2RotX = value; + updateShape(false); + }); + + gui + .add(model, "finalPrecision", 0.01, 1, 0.01) + .name("Final Precision") + .onFinishChange((value: number) => { + model.finalPrecision = value; + }); + + gui + .add(model, "rotationEnabled") + .name("Rotation Enabled") + .onFinishChange((value: boolean) => { + model.rotationEnabled = value; + }); + + gui + .add(model, "drawEdges") + .name("Draw Edges") + .onFinishChange((value: boolean) => { + model.drawEdges = value; + }); + + gui + .addColor(model, "color1") + .name("Color 1") + .onChange((value: string) => { + current.group1?.getChildren().forEach((c1) => { + const children = c1.getChildMeshes(); + const mat = children[0].material as PBRMetallicRoughnessMaterial; + mat.baseColor = Color3.FromHexString(value); + }); + }); + + gui + .addColor(model, "color2") + .name("Color 2") + .onChange((value: string) => { + current.group2?.getChildren().forEach((c1) => { + const children = c1.getChildMeshes(); + const mat = children[0].material as PBRMetallicRoughnessMaterial; + mat.baseColor = Color3.FromHexString(value); + }); + }); + + gui.add(model, "update").name("Finalize"); + gui.add(model, "downloadSTL").name("Download STL"); + gui.add(model, "downloadStep").name("Download STEP"); + gui.add(model, "downloadGLB").name("Download GLB"); +}; diff --git a/examples/vite/babylonjs/hex-shell/src/create-shape.ts b/examples/vite/babylonjs/hex-shell/src/helpers/create-shape.ts similarity index 96% rename from examples/vite/babylonjs/hex-shell/src/create-shape.ts rename to examples/vite/babylonjs/hex-shell/src/helpers/create-shape.ts index 55ea07ee..59dcf154 100644 --- a/examples/vite/babylonjs/hex-shell/src/create-shape.ts +++ b/examples/vite/babylonjs/hex-shell/src/helpers/create-shape.ts @@ -1,13 +1,13 @@ -import type { BitByBitBase } from '@bitbybit-dev/babylonjs'; +import type { BitByBitBase } from "@bitbybit-dev/babylonjs"; import { Color3, Mesh, PBRMetallicRoughnessMaterial, Scene, -} from '@babylonjs/core'; -import { Inputs } from '@bitbybit-dev/babylonjs'; -import type { Current } from './models/current'; -import type { Model } from './models/model'; +} from "@babylonjs/core"; +import { Inputs } from "@bitbybit-dev/babylonjs"; +import type { Current } from "../models/current"; +import type { Model } from "../models/model"; export const createShapeLod2 = async ( bitbybit: BitByBitBase | undefined, @@ -296,10 +296,10 @@ export const createShapeLod2 = async ( options.drawFaces = model.drawFaces; options.drawVertices = false; options.edgeWidth = 20; - options.edgeColour = '#000000'; + options.edgeColour = "#000000"; const mat = new PBRMetallicRoughnessMaterial( - 'mat1', + "mat1", bitbybit.context.scene ); mat.baseColor = Color3.FromHexString(model.color1); @@ -313,7 +313,7 @@ export const createShapeLod2 = async ( ); const mat2 = new PBRMetallicRoughnessMaterial( - 'mat2', + "mat2", bitbybit.context.scene ); mat2.baseColor = Color3.FromHexString(model.color2); @@ -329,10 +329,10 @@ export const createShapeLod2 = async ( const groups1 = await Promise.all(groups1Promises); const groups2 = await Promise.all(groups2Promises); - const group1 = new Mesh('group1', bitbybit.context.scene); + const group1 = new Mesh("group1", bitbybit.context.scene); groups1.forEach((g) => (g.parent = group1)); - const group2 = new Mesh('group2', bitbybit.context.scene); + const group2 = new Mesh("group2", bitbybit.context.scene); groups2.forEach((g) => (g.parent = group2)); current.group1 = group1; @@ -420,9 +420,9 @@ export const createShapeLod1 = async ( options.drawVertices = false; options.edgeWidth = 30; - options.edgeColour = '#ff00ff'; + options.edgeColour = "#ff00ff"; - const mat = new PBRMetallicRoughnessMaterial('mat', bitbybit.context.scene); + const mat = new PBRMetallicRoughnessMaterial("mat", bitbybit.context.scene); mat.baseColor = Color3.FromHexString(model.color1); mat.zOffset = 2; mat.backFaceCulling = false; @@ -433,7 +433,7 @@ export const createShapeLod1 = async ( }); const mat2 = new PBRMetallicRoughnessMaterial( - 'mat2', + "mat2", bitbybit.context.scene ); mat2.baseColor = Color3.FromHexString(model.color2); @@ -446,7 +446,7 @@ export const createShapeLod1 = async ( }); const dimOpt = new Inputs.Draw.DrawOcctShapeOptions(); - dimOpt.edgeColour = '#000000'; + dimOpt.edgeColour = "#000000"; dimOpt.edgeWidth = 20; dimOpt.drawFaces = false; const dimensionsGroup = await bitbybit.draw.drawAnyAsync({ @@ -457,10 +457,10 @@ export const createShapeLod1 = async ( // just to match chunked data structure of LOD2 - const group1 = new Mesh('group1', bitbybit.context.scene); + const group1 = new Mesh("group1", bitbybit.context.scene); grp1.parent = group1; - const group2 = new Mesh('group2', bitbybit.context.scene); + const group2 = new Mesh("group2", bitbybit.context.scene); grp2.parent = group2; current.group1 = group1; @@ -550,7 +550,7 @@ async function createDimensions( linearOptions.labelSize = 3; linearOptions.labelOffset = 3; linearOptions.crossingSize = 1; - linearOptions.labelSuffix = '(m)'; + linearOptions.labelSuffix = "(m)"; const dimLength = await dimensions.simpleLinearLengthDimension(linearOptions); shapesToClean.push(dimLength); diff --git a/examples/vite/babylonjs/hex-shell/src/helpers/downloads.ts b/examples/vite/babylonjs/hex-shell/src/helpers/downloads.ts new file mode 100644 index 00000000..6875dc3f --- /dev/null +++ b/examples/vite/babylonjs/hex-shell/src/helpers/downloads.ts @@ -0,0 +1,39 @@ +import type { BitByBitBase, Inputs } from "@bitbybit-dev/babylonjs"; + +export const downloadStep = async ( + bitbybit: BitByBitBase, + finalShape: Inputs.OCCT.TopoDSShapePointer | undefined +) => { + if (bitbybit && finalShape) { + await bitbybit.occt.io.saveShapeSTEP({ + shape: finalShape, + fileName: "shape", + adjustYtoZ: true, + tryDownload: true, + }); + } +}; + +export const downloadSTL = ( + bitbybit: BitByBitBase, + finalShape: Inputs.OCCT.TopoDSShapePointer | undefined +) => { + if (bitbybit && finalShape) { + bitbybit.occt.io.saveShapeStl({ + fileName: "bitbybit-hex-shell.stl", + shape: finalShape, + adjustYtoZ: true, + tryDownload: true, + precision: 0.01, + }); + } +}; + +export const downloadGLB = (bitbybit: BitByBitBase) => { + if (bitbybit) { + bitbybit.babylon.io.exportGLB({ + fileName: "bitbybit-hex-shell.glb", + discardSkyboxAndGrid: true, + }); + } +}; diff --git a/examples/vite/babylonjs/hex-shell/src/helpers/gui-helper.ts b/examples/vite/babylonjs/hex-shell/src/helpers/gui-helper.ts new file mode 100644 index 00000000..df077efa --- /dev/null +++ b/examples/vite/babylonjs/hex-shell/src/helpers/gui-helper.ts @@ -0,0 +1,31 @@ +export function disableGUI() { + const lilGui = document.getElementsByClassName("lil-gui")[0] as HTMLElement; + lilGui.style.pointerEvents = "none"; + lilGui.style.opacity = "0.5"; +} + +export function enableGUI() { + const lilGui = document.getElementsByClassName("lil-gui")[0] as HTMLElement; + lilGui.style.pointerEvents = "all"; + lilGui.style.opacity = "1"; +} + +export function showSpinner() { + const element = document.createElement("div"); + element.id = "spinner"; + element.className = "lds-ellipsis"; + element.innerHTML = ` +
+
+
+`; + + document.body.appendChild(element); +} + +export function hideSpinner() { + const el = document.getElementById("spinner"); + if (el) { + el.remove(); + } +} diff --git a/examples/vite/babylonjs/hex-shell/src/helpers/index.ts b/examples/vite/babylonjs/hex-shell/src/helpers/index.ts new file mode 100644 index 00000000..b717f152 --- /dev/null +++ b/examples/vite/babylonjs/hex-shell/src/helpers/index.ts @@ -0,0 +1,7 @@ +export * from "./create-gui"; +export * from "./create-shape"; +export * from "./init-kernels"; +export * from "./init-babylonjs"; +export * from "./downloads"; +export * from "./gui-helper"; +export * from "./downloads"; diff --git a/examples/vite/babylonjs/hex-shell/src/helpers/init-babylonjs.ts b/examples/vite/babylonjs/hex-shell/src/helpers/init-babylonjs.ts new file mode 100644 index 00000000..ee9d78a1 --- /dev/null +++ b/examples/vite/babylonjs/hex-shell/src/helpers/init-babylonjs.ts @@ -0,0 +1,77 @@ +import { + Scene, + TransformNode, + ArcRotateCamera, + Vector3, + HemisphericLight, + Color3, + Engine, + Color4, + Light, + MeshBuilder, + PBRMetallicRoughnessMaterial, +} from "@babylonjs/core"; +import type { Current } from "../models"; +import { Inputs, type BitByBitBase } from "@bitbybit-dev/babylonjs"; + +export function initBabylonJS() { + const canvas = document.getElementById("babylon-canvas") as HTMLCanvasElement; + canvas.addEventListener("wheel", (evt) => evt.preventDefault()); + const engine = new Engine(canvas, true); + engine.setHardwareScalingLevel(0.5); + const scene = new Scene(engine); + scene.clearColor = Color4.FromHexString("#8888ff"); + new TransformNode("root", scene); + const camera = new ArcRotateCamera( + "Camera", + 0, + 10, + 10, + new Vector3(0, 0, 0), + scene + ); + const camPos = new Vector3(150, 15, 60); + camera.setPosition(camPos); + const camTarget = new Vector3(0, 5, 0); + camera.setTarget(camTarget); + camera.attachControl(canvas, true); + camera.lowerRadiusLimit = 0; + camera.minZ = 3; + const light = new HemisphericLight("HemiLight", new Vector3(0, 1, 0), scene); + light.intensityMode = Light.INTENSITYMODE_ILLUMINANCE; + light.intensity = 1; + + scene.ambientColor = Color3.FromHexString("#ffffff"); + scene.metadata = { shadowGenerators: [] }; + + window.onresize = () => { + engine.resize(); + }; + + return { scene, engine, camera }; +} + +export function createDirLightsAndGround( + bitbybit: BitByBitBase, + current: Current +) { + const dirLightOpt = new Inputs.BabylonScene.DirectionalLightDto(); + dirLightOpt.intensity = 3; + dirLightOpt.shadowGeneratorMapSize = 4000; + dirLightOpt.shadowBias = 0.001; + dirLightOpt.direction = [50, -50, -100]; + bitbybit.babylon.scene.drawDirectionalLight(dirLightOpt); + + const matGround = new PBRMetallicRoughnessMaterial("ground"); + matGround.baseColor = Color3.FromHexString("#8888ff"); + matGround.zOffset = 2; + const ground = MeshBuilder.CreateCylinder("ground", { + diameter: 250, + height: 3, + tessellation: 300, + }); + ground.position.y = -1.5; + ground.material = matGround; + ground.receiveShadows = true; + current.ground = ground; +} diff --git a/examples/vite/babylonjs/hex-shell/src/helpers/init-kernels.ts b/examples/vite/babylonjs/hex-shell/src/helpers/init-kernels.ts new file mode 100644 index 00000000..cb319e39 --- /dev/null +++ b/examples/vite/babylonjs/hex-shell/src/helpers/init-kernels.ts @@ -0,0 +1,125 @@ +import type { BitByBitBase } from "@bitbybit-dev/babylonjs"; +import type { Scene } from "@babylonjs/core"; +import type { KernelOptions } from "../models"; +import { first, firstValueFrom, tap } from "rxjs"; +import { OccStateEnum } from "@bitbybit-dev/occt-worker"; +import { JscadStateEnum } from "@bitbybit-dev/jscad-worker"; +import { ManifoldStateEnum } from "@bitbybit-dev/manifold-worker"; + +export async function initKernels( + scene: Scene, + bitbybit: BitByBitBase, + options: KernelOptions +): Promise<{ message: string }> { + let occtWorkerInstance: Worker | undefined; + let jscadWorkerInstance: Worker | undefined; + let manifoldWorkerInstance: Worker | undefined; + + // 1. Conditionally create worker instances + if (options.enableOCCT) { + occtWorkerInstance = new Worker( + new URL("../workers/occt.worker.ts", import.meta.url), + { name: "OCC_WORKER", type: "module" } + ); + } + if (options.enableJSCAD) { + jscadWorkerInstance = new Worker( + new URL("../workers/jscad.worker.ts", import.meta.url), + { name: "JSCAD_WORKER", type: "module" } + ); + } + if (options.enableManifold) { + manifoldWorkerInstance = new Worker( + new URL("../workers/manifold.worker.ts", import.meta.url), + { name: "MANIFOLD_WORKER", type: "module" } + ); + } + + // 2. Initialize Bitbybit + await bitbybit.init( + scene, + occtWorkerInstance, + jscadWorkerInstance, + manifoldWorkerInstance + ); + + // 3. Collect promises for kernel initializations + const initializationPromises: Promise[] = []; + let anyKernelSelectedForInit = false; + + if (options.enableOCCT) { + anyKernelSelectedForInit = true; + if (bitbybit.occtWorkerManager) { + initializationPromises.push( + firstValueFrom( + bitbybit.occtWorkerManager.occWorkerState$.pipe( + first((s) => s.state === OccStateEnum.initialised), + tap(() => console.log("OCCT Initialized")) + ) + ).then(() => {}) // Ensure the promise resolves to void for Promise.all + ); + } else { + console.warn( + "OCCT enabled in options, but occtWorkerManager not found after init." + ); + } + } + + if (options.enableJSCAD) { + anyKernelSelectedForInit = true; + if (bitbybit.jscadWorkerManager) { + initializationPromises.push( + firstValueFrom( + bitbybit.jscadWorkerManager.jscadWorkerState$.pipe( + first((s) => s.state === JscadStateEnum.initialised), + tap(() => console.log("JSCAD Initialized")) + ) + ).then(() => {}) + ); + } else { + console.warn( + "JSCAD enabled in options, but jscadWorkerManager not found after init." + ); + } + } + + if (options.enableManifold) { + anyKernelSelectedForInit = true; + if (bitbybit.manifoldWorkerManager) { + initializationPromises.push( + firstValueFrom( + bitbybit.manifoldWorkerManager.manifoldWorkerState$.pipe( + first((s) => s.state === ManifoldStateEnum.initialised), + tap(() => console.log("Manifold Initialized")) + ) + ).then(() => {}) + ); + } else { + console.warn( + "Manifold enabled in options, but manifoldWorkerManager not found after init." + ); + } + } + + // 4. Wait for selected & available kernels or handle no selection/availability + if (!anyKernelSelectedForInit) { + console.log("No kernels selected for initialization."); + return { message: "No kernels selected for initialization." }; + } + + if (initializationPromises.length === 0) { + // Kernels were selected, but none were awaitable (e.g., managers missing for all selected) + console.log( + "Kernels were selected, but none had managers available for awaiting initialization." + ); + return { + message: "Selected kernels were not awaitable for initialization state.", + }; + } + + await Promise.all(initializationPromises); + console.log("Selected and awaitable kernels initialized:", options); + return { + message: "Selected and awaitable kernels initialized successfully.", + }; +} diff --git a/examples/vite/babylonjs/hex-shell/src/main.ts b/examples/vite/babylonjs/hex-shell/src/main.ts index 9820b934..f2f49e50 100644 --- a/examples/vite/babylonjs/hex-shell/src/main.ts +++ b/examples/vite/babylonjs/hex-shell/src/main.ts @@ -1,66 +1,48 @@ import './style.css'; -import { BitByBitBase } from '@bitbybit-dev/babylonjs'; -import { OccStateEnum } from '@bitbybit-dev/occt-worker'; -import { Inputs } from '@bitbybit-dev/babylonjs'; -import { GUI } from 'lil-gui'; -import { createShapeLod2, createShapeLod1 } from './create-shape'; -import type { Current } from './models/current'; -import type { Model } from './models/model'; +import { BitByBitBase, Inputs } from '@bitbybit-dev/babylonjs'; +import { model, type KernelOptions, current } from './models'; import { - Scene, - ArcRotateCamera, - Engine, - WebGPUEngine, - Vector3, - Color4, - Color3, - TransformNode, - HemisphericLight, - Light, - PBRMetallicRoughnessMaterial, - MeshBuilder, -} from '@babylonjs/core'; + initKernels, + initBabylonJS, + createGui, + createShapeLod1, + createShapeLod2, + createDirLightsAndGround, + disableGUI, + enableGUI, + hideSpinner, + showSpinner, + downloadGLB, + downloadSTL, + downloadStep, +} from './helpers'; + +const kernelOptions: KernelOptions = { + enableOCCT: true, + enableJSCAD: false, + enableManifold: false, +}; + +start(); + +async function start() { + const { scene, engine } = initBabylonJS(); + + const bitbybit = new BitByBitBase(); + bitbybit.context.scene = scene; + bitbybit.context.engine = engine; + createDirLightsAndGround(bitbybit, current); + + await initKernels(scene, bitbybit, kernelOptions); -document.querySelector('#app')!.innerHTML = ` - - -`; + let finalShape: Inputs.OCCT.TopoDSShapePointer | undefined; + let shapesToClean: Inputs.OCCT.TopoDSShapePointer[] = []; -function component() { - let current: Current = { - group1: undefined, - group2: undefined, - dimensions: undefined, - ground: undefined, - light1: undefined, - gui: undefined, - }; + model.downloadStep = () => downloadStep(bitbybit, finalShape); + model.downloadGLB = () => downloadGLB(bitbybit); + model.downloadSTL = () => downloadSTL(bitbybit, finalShape); - const model = { - uHex: 3, - vHex: 12, - height: 15, - ellipse1MinRad: 15, - ellipse1MaxRad: 15, - ellipse2MinRad: 25, - ellipse2MaxRad: 30, - ellipse2RotX: 15, - ellipse2RotY: 15, - ellipse3MinRad: 45, - ellipse3MaxRad: 90, - ellipse3YRot: 45, - finalPrecision: 0.05, - drawEdges: false, - drawFaces: true, - rotationEnabled: false, - color1: '#ffffff', - color2: '#8000ff', - } as Model; - - let shapesToClean: Inputs.OCCT.TopoDSShapePointer[] = []; - let finalShape: Inputs.OCCT.TopoDSShapePointer | undefined; - let bitbybit: BitByBitBase | undefined; - let scene: Scene | undefined; + createGui(current, model, updateShape); const rotationSpeed = 0.0005; const rotateGroup = () => { @@ -70,49 +52,27 @@ function component() { current.group2 && current.dimensions ) { - current.group1.rotation.y += rotationSpeed; - current.group2.rotation.y += rotationSpeed; - current.dimensions.rotation.y += rotationSpeed; - } - }; - - const downloadStep = async () => { - if (bitbybit && finalShape) { - await bitbybit.occt.io.saveShapeSTEP({ - shape: finalShape, - fileName: 'shape', - adjustYtoZ: true, - tryDownload: true, - }); + current.group1.rotation.y -= rotationSpeed; + current.group2.rotation.y -= rotationSpeed; + current.dimensions.rotation.y -= rotationSpeed; } }; - const downloadSTL = () => { - if (scene && bitbybit && finalShape) { - bitbybit.occt.io.saveShapeStl({ - fileName: 'bitbybit-hex-shell.stl', - shape: finalShape, - adjustYtoZ: true, - tryDownload: true, - precision: 0.01, - }); - } - }; + scene.onBeforeRenderObservable.add(() => rotateGroup()); - const downloadGLB = () => { - if (scene && bitbybit) { - bitbybit.babylon.io.exportGLB({ - fileName: 'bitbybit-hex-shell.glb', - discardSkyboxAndGrid: true, - }); - } - }; + engine.runRenderLoop(() => { + scene.render(true, false); + }); - model.downloadGLB = downloadGLB; - model.downloadSTL = downloadSTL; - model.downloadStep = downloadStep; + finalShape = await createShapeLod1( + bitbybit, + scene, + model, + shapesToClean, + current + ); - const updateShape = async (finish: boolean) => { + async function updateShape(finish: boolean) { disableGUI(); showSpinner(); current.group1?.dispose(false, true); @@ -138,228 +98,5 @@ function component() { } hideSpinner(); enableGUI(); - }; - - model.update = () => updateShape(true); - - const init = async () => { - bitbybit = new BitByBitBase(); - - const occt = new Worker(new URL('./workers/occt.worker', import.meta.url), { - name: 'OCC', - type: 'module', - }); - - const canvas = document.getElementById( - 'babylon-canvas' - ) as HTMLCanvasElement; - canvas.addEventListener('wheel', (evt) => evt.preventDefault()); - const engine = new Engine(canvas, true); - engine.setHardwareScalingLevel(0.5); - const { scn } = initScene(bitbybit, engine, canvas); - scene = scn; - - bitbybit.init(scene, occt); - - const dirLightOpt = new Inputs.BabylonScene.DirectionalLightDto(); - dirLightOpt.intensity = 3; - dirLightOpt.shadowGeneratorMapSize = 4000; - dirLightOpt.shadowBias = 0.001; - dirLightOpt.direction = [50, -50, -100]; - bitbybit.babylon.scene.drawDirectionalLight(dirLightOpt); - - const matGround = new PBRMetallicRoughnessMaterial('ground'); - matGround.baseColor = Color3.FromHexString('#8888ff'); - matGround.zOffset = 2; - const ground = MeshBuilder.CreateCylinder('ground', { - diameter: 250, - height: 3, - tessellation: 300, - }); - ground.position.y = -1.5; - ground.material = matGround; - ground.receiveShadows = true; - current.ground = ground; - - window.onresize = () => { - engine.resize(); - }; - - bitbybit.occtWorkerManager.occWorkerState$.subscribe(async (s) => { - if (s.state === OccStateEnum.initialised) { - finalShape = await createShapeLod1( - bitbybit, - scene, - model, - shapesToClean, - current - ); - - createGui(); - } - }); - - engine.runRenderLoop(() => { - bitbybit?.context.scene?.render(true, false); - rotateGroup(); - }); - }; - - function initScene( - bitbybit: BitByBitBase, - engine: Engine | WebGPUEngine, - canvas: HTMLCanvasElement - ) { - const scn = new Scene(engine); - scn.clearColor = Color4.FromHexString('#8888ff'); - new TransformNode('root', scn); - const camera = new ArcRotateCamera( - 'Camera', - 0, - 10, - 10, - new Vector3(0, 0, 0), - scn - ); - const camPos = new Vector3(150, 15, 60); - camera.setPosition(camPos); - const camTarget = new Vector3(0, 5, 0); - camera.setTarget(camTarget); - camera.attachControl(canvas, true); - camera.lowerRadiusLimit = 0; - camera.minZ = 3; - const light = new HemisphericLight('HemiLight', new Vector3(0, 1, 0), scn); - light.intensityMode = Light.INTENSITYMODE_ILLUMINANCE; - light.intensity = 1; - - scn.ambientColor = Color3.FromHexString('#ffffff'); - scn.metadata = { shadowGenerators: [] }; - - bitbybit.context.scene = scn; - bitbybit.context.engine = engine; - - return { scn, camera }; - } - - const disableGUI = () => { - const lilGui = document.getElementsByClassName('lil-gui')[0] as HTMLElement; - lilGui.style.pointerEvents = 'none'; - lilGui.style.opacity = '0.5'; - }; - - const enableGUI = () => { - const lilGui = document.getElementsByClassName('lil-gui')[0] as HTMLElement; - lilGui.style.pointerEvents = 'all'; - lilGui.style.opacity = '1'; - }; - - function showSpinner() { - const element = document.createElement('div'); - element.id = 'spinner'; - element.className = 'lds-ellipsis'; - element.innerHTML = ` -
-
-
- `; - - document.body.appendChild(element); } - - function hideSpinner() { - const el = document.getElementById('spinner'); - if (el) { - el.remove(); - } - } - - const createGui = () => { - const gui = new GUI(); - current.gui = gui; - gui.$title.innerHTML = 'Pattern'; - - gui - .add(model, 'uHex', 1, 14, 1) - .name('Hexagons U') - .onFinishChange((value: number) => { - model.uHex = value; - updateShape(false); - }); - - gui - .add(model, 'vHex', 8, 36, 2) - .name('Hexagons V') - .onFinishChange((value: number) => { - model.vHex = value; - updateShape(false); - }); - - gui - .add(model, 'height', 15, 25, 1) - .name('Height') - .onFinishChange((value: number) => { - model.height = value; - updateShape(false); - }); - - gui - .add(model, 'ellipse2RotX', 0, 15, 0.1) - .name('Angle Guide') - .onFinishChange((value: number) => { - model.ellipse2RotX = value; - updateShape(false); - }); - - gui - .add(model, 'finalPrecision', 0.01, 1, 0.01) - .name('Final Precision') - .onFinishChange((value: number) => { - model.finalPrecision = value; - }); - - gui - .add(model, 'rotationEnabled') - .name('Rotation Enabled') - .onFinishChange((value: boolean) => { - model.rotationEnabled = value; - }); - - gui - .add(model, 'drawEdges') - .name('Draw Edges') - .onFinishChange((value: boolean) => { - model.drawEdges = value; - }); - - gui - .addColor(model, 'color1') - .name('Color 1') - .onChange((value: string) => { - current.group1?.getChildren().forEach((c1) => { - const children = c1.getChildMeshes(); - const mat = children[0].material as PBRMetallicRoughnessMaterial; - mat.baseColor = Color3.FromHexString(value); - }); - }); - - gui - .addColor(model, 'color2') - .name('Color 2') - .onChange((value: string) => { - current.group2?.getChildren().forEach((c1) => { - const children = c1.getChildMeshes(); - const mat = children[0].material as PBRMetallicRoughnessMaterial; - mat.baseColor = Color3.FromHexString(value); - }); - }); - - gui.add(model, 'update').name('Finalize'); - gui.add(model, 'downloadSTL').name('Download STL'); - gui.add(model, 'downloadStep').name('Download STEP'); - gui.add(model, 'downloadGLB').name('Download GLB'); - }; - - init(); } - -component(); diff --git a/examples/vite/babylonjs/hex-shell/src/models/current.ts b/examples/vite/babylonjs/hex-shell/src/models/current.ts index 1531172f..78a0459f 100644 --- a/examples/vite/babylonjs/hex-shell/src/models/current.ts +++ b/examples/vite/babylonjs/hex-shell/src/models/current.ts @@ -1,5 +1,5 @@ -import { DirectionalLight, Mesh } from '@babylonjs/core'; -import { GUI } from 'lil-gui'; +import { DirectionalLight, Mesh } from "@babylonjs/core"; +import { GUI } from "lil-gui"; export type Current = { group1: Mesh | undefined; @@ -9,3 +9,12 @@ export type Current = { ground: Mesh | undefined; gui: GUI | undefined; }; + +export const current: Current = { + group1: undefined, + group2: undefined, + dimensions: undefined, + ground: undefined, + light1: undefined, + gui: undefined, +}; diff --git a/examples/vite/babylonjs/hex-shell/src/models/index.ts b/examples/vite/babylonjs/hex-shell/src/models/index.ts new file mode 100644 index 00000000..23e3b232 --- /dev/null +++ b/examples/vite/babylonjs/hex-shell/src/models/index.ts @@ -0,0 +1,3 @@ +export * from "./current"; +export * from "./kernel-options"; +export * from "./model"; diff --git a/examples/vite/babylonjs/hex-shell/src/models/kernel-options.ts b/examples/vite/babylonjs/hex-shell/src/models/kernel-options.ts new file mode 100644 index 00000000..613e4575 --- /dev/null +++ b/examples/vite/babylonjs/hex-shell/src/models/kernel-options.ts @@ -0,0 +1,5 @@ +export interface KernelOptions { + enableOCCT: boolean; + enableJSCAD: boolean; + enableManifold: boolean; +} diff --git a/examples/vite/babylonjs/hex-shell/src/models/model.ts b/examples/vite/babylonjs/hex-shell/src/models/model.ts index 5260fda4..64b2f15c 100644 --- a/examples/vite/babylonjs/hex-shell/src/models/model.ts +++ b/examples/vite/babylonjs/hex-shell/src/models/model.ts @@ -1,3 +1,6 @@ +import type { BitByBitBase, Inputs } from "@bitbybit-dev/babylonjs"; +import type { Scene } from "@babylonjs/core"; + export type Model = { uHex: number; vHex: number; @@ -17,8 +20,32 @@ export type Model = { color2: string; finalPrecision: number; rotationEnabled: boolean; - downloadSTL?: () => void; - downloadStep?: () => void; - downloadGLB?: () => void; + downloadSTL?: (scene: Scene) => void; + downloadStep?: ( + bitbybit: BitByBitBase, + finalShape: Inputs.OCCT.TopoDSShapePointer | undefined + ) => void; + downloadGLB?: (scene: Scene) => void; update?: () => void; }; + +export const model = { + uHex: 3, + vHex: 12, + height: 15, + ellipse1MinRad: 15, + ellipse1MaxRad: 15, + ellipse2MinRad: 25, + ellipse2MaxRad: 30, + ellipse2RotX: 15, + ellipse2RotY: 15, + ellipse3MinRad: 45, + ellipse3MaxRad: 90, + ellipse3YRot: 45, + finalPrecision: 0.05, + drawEdges: false, + drawFaces: true, + rotationEnabled: false, + color1: "#b3ccff", + color2: "#ffffff", +} as Model; diff --git a/examples/vite/babylonjs/hex-shell/src/style.css b/examples/vite/babylonjs/hex-shell/src/style.css index d8f967e9..fe270910 100644 --- a/examples/vite/babylonjs/hex-shell/src/style.css +++ b/examples/vite/babylonjs/hex-shell/src/style.css @@ -1,103 +1,104 @@ body { - margin: 0px; - overflow: hidden; + margin: 0px; + overflow: hidden; } #babylon-canvas { - width: 100%; - height: 100%; - overflow: hidden; - position: absolute; - outline: none; + width: 100%; + height: 100%; + overflow: hidden; + position: absolute; + outline: none; } a.logo { - position: absolute; - color: white; - vertical-align: middle; - bottom: 10px; - left: 10px; - font-family: 'Courier New', Courier, monospace; - text-decoration: none; - width: 100%; + z-index: 1; + position: absolute; + color: white; + vertical-align: middle; + bottom: 10px; + left: 10px; + font-family: 'Courier New', Courier, monospace; + text-decoration: none; + width: 100%; } .logo { - margin-bottom: 20px; - text-align: center; + margin-bottom: 20px; + text-align: center; } .logo img { - width: 50px; - height: 50px; + width: 50px; + height: 50px; } .lds-ellipsis { - z-index: 2; - top: calc(50% - 32px); - left: calc(50% - 32px); - display: inline-block; - position: absolute; - width: 64px; - height: 64px; + z-index: 2; + top: calc(50% - 32px); + left: calc(50% - 32px); + display: inline-block; + position: absolute; + width: 64px; + height: 64px; } .lds-ellipsis div { - position: absolute; - top: 27px; - width: 11px; - height: 11px; - border-radius: 50%; - background: rgba(255, 255, 255, 0.8); - animation-timing-function: cubic-bezier(0, 1, 1, 0); + position: absolute; + top: 27px; + width: 11px; + height: 11px; + border-radius: 50%; + background: rgba(255, 255, 255, 0.8); + animation-timing-function: cubic-bezier(0, 1, 1, 0); } .lds-ellipsis div:nth-child(1) { - left: 6px; - animation: lds-ellipsis1 0.6s infinite; + left: 6px; + animation: lds-ellipsis1 0.6s infinite; } .lds-ellipsis div:nth-child(2) { - left: 6px; - animation: lds-ellipsis2 0.6s infinite; + left: 6px; + animation: lds-ellipsis2 0.6s infinite; } .lds-ellipsis div:nth-child(3) { - left: 26px; - animation: lds-ellipsis2 0.6s infinite; + left: 26px; + animation: lds-ellipsis2 0.6s infinite; } .lds-ellipsis div:nth-child(4) { - left: 45px; - animation: lds-ellipsis3 0.6s infinite; + left: 45px; + animation: lds-ellipsis3 0.6s infinite; } @keyframes lds-ellipsis1 { - 0% { - transform: scale(0); - } + 0% { + transform: scale(0); + } - 100% { - transform: scale(1); - } + 100% { + transform: scale(1); + } } @keyframes lds-ellipsis3 { - 0% { - transform: scale(1); - } + 0% { + transform: scale(1); + } - 100% { - transform: scale(0); - } + 100% { + transform: scale(0); + } } @keyframes lds-ellipsis2 { - 0% { - transform: translate(0, 0); - } - - 100% { - transform: translate(19px, 0); - } -} + 0% { + transform: translate(0, 0); + } + + 100% { + transform: translate(19px, 0); + } +} \ No newline at end of file diff --git a/examples/vite/babylonjs/hex-shell/src/workers/jscad.worker.ts b/examples/vite/babylonjs/hex-shell/src/workers/jscad.worker.ts index 5ee5cda1..eeed36fd 100644 --- a/examples/vite/babylonjs/hex-shell/src/workers/jscad.worker.ts +++ b/examples/vite/babylonjs/hex-shell/src/workers/jscad.worker.ts @@ -1,12 +1,12 @@ import { initializationComplete, onMessageInput, -} from '@bitbybit-dev/jscad-worker'; +} from "@bitbybit-dev/jscad-worker"; -import('@bitbybit-dev/jscad/jscad-generated').then((s) => { +import("@bitbybit-dev/jscad/jscad-generated").then((s) => { initializationComplete(s.default()); }); -addEventListener('message', ({ data }) => { +addEventListener("message", ({ data }) => { onMessageInput(data, postMessage); }); diff --git a/examples/vite/babylonjs/hex-shell/src/workers/manifold.worker.ts b/examples/vite/babylonjs/hex-shell/src/workers/manifold.worker.ts index a7302543..889fad80 100644 --- a/examples/vite/babylonjs/hex-shell/src/workers/manifold.worker.ts +++ b/examples/vite/babylonjs/hex-shell/src/workers/manifold.worker.ts @@ -1,13 +1,13 @@ import { initializationComplete, onMessageInput, -} from '@bitbybit-dev/manifold-worker'; -import Module from 'manifold-3d'; +} from "@bitbybit-dev/manifold-worker"; +import Module from "manifold-3d"; const init = async () => { const wasm = await Module({ locateFile: () => { - return 'https://cdn.jsdelivr.net/gh/bitbybit-dev/bitbybit-assets@0.20.2/wasm/manifold.cc2ddd38.wasm'; + return "https://cdn.jsdelivr.net/gh/bitbybit-dev/bitbybit-assets@0.20.2/wasm/manifold.cc2ddd38.wasm"; }, }); wasm.setup(); @@ -16,6 +16,6 @@ const init = async () => { init(); -addEventListener('message', ({ data }) => { +addEventListener("message", ({ data }) => { onMessageInput(data, postMessage); }); diff --git a/examples/vite/babylonjs/hex-shell/src/workers/occt.worker.ts b/examples/vite/babylonjs/hex-shell/src/workers/occt.worker.ts index f613669d..492dfd44 100644 --- a/examples/vite/babylonjs/hex-shell/src/workers/occt.worker.ts +++ b/examples/vite/babylonjs/hex-shell/src/workers/occt.worker.ts @@ -1,14 +1,14 @@ -import initOpenCascade from '@bitbybit-dev/occt/bitbybit-dev-occt/cdn'; -import type { OpenCascadeInstance } from '@bitbybit-dev/occt/bitbybit-dev-occt/bitbybit-dev-occt.js'; +import initOpenCascade from "@bitbybit-dev/occt/bitbybit-dev-occt/cdn"; +import type { OpenCascadeInstance } from "@bitbybit-dev/occt/bitbybit-dev-occt/bitbybit-dev-occt.js"; import { initializationComplete, onMessageInput, -} from '@bitbybit-dev/occt-worker'; +} from "@bitbybit-dev/occt-worker"; initOpenCascade().then((occ: OpenCascadeInstance) => { initializationComplete(occ, undefined); }); -addEventListener('message', ({ data }) => { +addEventListener("message", ({ data }) => { onMessageInput(data, postMessage); }); diff --git a/examples/vite/threejs/hex-shell/index.html b/examples/vite/threejs/hex-shell/index.html index c7a81179..70b1766a 100644 --- a/examples/vite/threejs/hex-shell/index.html +++ b/examples/vite/threejs/hex-shell/index.html @@ -4,7 +4,7 @@ - Bitbybit & ThreeJS CAD Example + Bitbybit & ThreeJS Hex Shell Example
support the mission - subscribe
-
+ diff --git a/examples/vite/threejs/hex-shell/package-lock.json b/examples/vite/threejs/hex-shell/package-lock.json index 21240e3b..cf5eb074 100644 --- a/examples/vite/threejs/hex-shell/package-lock.json +++ b/examples/vite/threejs/hex-shell/package-lock.json @@ -1,7 +1,7 @@ { "name": "vite-typescript-starter", "version": "0.0.0", - "lockfileVersion": 3, + "lockfileVersion": 2, "requires": true, "packages": { "": { @@ -20,12 +20,14 @@ "node_modules/@bitbybit-dev/base": { "version": "0.20.4", "resolved": "https://registry.npmjs.org/@bitbybit-dev/base/-/base-0.20.4.tgz", - "integrity": "sha512-yMsOkUFrm9JIGC3Bs49bu1I/gqwQNK8nVO3XgesOpzZvVQOF5OTxCheiQnrqiUw9DiiPuKw1T0gXBMwThzwdOw==" + "integrity": "sha512-yMsOkUFrm9JIGC3Bs49bu1I/gqwQNK8nVO3XgesOpzZvVQOF5OTxCheiQnrqiUw9DiiPuKw1T0gXBMwThzwdOw==", + "license": "MIT" }, "node_modules/@bitbybit-dev/core": { "version": "0.20.4", "resolved": "https://registry.npmjs.org/@bitbybit-dev/core/-/core-0.20.4.tgz", "integrity": "sha512-T2hOHzvI+ikNxQRvhDyk/TeMCBhjZPY+wLmRSbYHiWnNGP5+3GCesZyb672XfEwPIWRH2kBS4vyp9R9fRnJujQ==", + "license": "MIT", "dependencies": { "@bitbybit-dev/base": "0.20.4", "@bitbybit-dev/jscad-worker": "0.20.4", @@ -40,6 +42,7 @@ "version": "0.20.4", "resolved": "https://registry.npmjs.org/@bitbybit-dev/jscad/-/jscad-0.20.4.tgz", "integrity": "sha512-e7/7Ag796rwn58H6Nu0lzhDkim+rJTqMWCqFZquNswoX2qqZXCv8azyOFE2LqfTvyIsEeJr/VEWIy2nvmtJnmg==", + "license": "MIT", "dependencies": { "@bitbybit-dev/base": "0.20.4", "@jscad/3mf-serializer": "2.1.12", @@ -53,6 +56,7 @@ "version": "0.20.4", "resolved": "https://registry.npmjs.org/@bitbybit-dev/jscad-worker/-/jscad-worker-0.20.4.tgz", "integrity": "sha512-DsjL2YO6urR8B/8LKYRrk4q9hAJE8oB+e5m+LDDBXbl7Vl0CHdC5ogPm6w07RcAHdSbMJouf2Ow7nGP/oOcjEg==", + "license": "MIT", "dependencies": { "@bitbybit-dev/jscad": "0.20.4", "rxjs": "7.5.5" @@ -62,6 +66,7 @@ "version": "0.20.4", "resolved": "https://registry.npmjs.org/@bitbybit-dev/manifold/-/manifold-0.20.4.tgz", "integrity": "sha512-rEGO8wOd/RUWPIRWdyE70w79JXhQ1iV6mACBuOH8/UD7+vf9wkk3KLWAYCzVPJP1nvx4+/SKCvU7e1JxEzq0Qw==", + "license": "MIT", "dependencies": { "manifold-3d": "3.0.0" } @@ -70,6 +75,7 @@ "version": "0.20.4", "resolved": "https://registry.npmjs.org/@bitbybit-dev/manifold-worker/-/manifold-worker-0.20.4.tgz", "integrity": "sha512-mwU87fg8M3p472dn/RiuveiPtq/IuOWCcoG0uismEE2g+rnciMrCSUSkXMkfXDCk9l0ZqoVfYg+dHVx0KBHBUg==", + "license": "MIT", "dependencies": { "@bitbybit-dev/manifold": "0.20.4", "rxjs": "7.5.5" @@ -79,6 +85,7 @@ "version": "0.20.4", "resolved": "https://registry.npmjs.org/@bitbybit-dev/occt/-/occt-0.20.4.tgz", "integrity": "sha512-Lxx4wsToS3EIiS2L3KjUh6Jpgvxsyxbh2Jt4raWhIbD9PSy1zRfMww9K7xFlawSMgq12WN1a0lV8ydKs1f5/zw==", + "license": "MIT", "dependencies": { "@bitbybit-dev/base": "0.20.4" } @@ -87,6 +94,7 @@ "version": "0.20.4", "resolved": "https://registry.npmjs.org/@bitbybit-dev/occt-worker/-/occt-worker-0.20.4.tgz", "integrity": "sha512-R5fiGteBSitv89Pz3XVgs+Vv0c1uH477oihkw1EUWLDTa7ypiXOohpjlKYFd/qAy3QCe8GEF3jDT+TK3dsQ+FA==", + "license": "MIT", "dependencies": { "@bitbybit-dev/occt": "0.20.4", "rxjs": "7.5.5" @@ -96,6 +104,7 @@ "version": "0.20.4", "resolved": "https://registry.npmjs.org/@bitbybit-dev/threejs/-/threejs-0.20.4.tgz", "integrity": "sha512-kGRZDQFCmN6qEWeR62bniTT+kMJTzheRA0l3AIUOFzgKX5ZMxeV0lUv6gZgLnKHOLniC+Aa1o7p2uLQjGjD2MA==", + "license": "MIT", "dependencies": { "@bitbybit-dev/core": "0.20.4", "three": "0.176.0" @@ -105,12 +114,13 @@ "version": "0.12.0", "resolved": "https://registry.npmjs.org/@dimforge/rapier3d-compat/-/rapier3d-compat-0.12.0.tgz", "integrity": "sha512-uekIGetywIgopfD97oDL5PfeezkFpNhwlzlaEYNOA0N6ghdsOvh/HYjSMek5Q2O1PYvRSDFcqFVJl4r4ZBwOow==", - "dev": true + "dev": true, + "license": "Apache-2.0" }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.4.tgz", - "integrity": "sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.3.tgz", + "integrity": "sha512-W8bFfPA8DowP8l//sxjJLSLkD8iEjMc7cBVyP+u4cEv9sM7mdUCkgsj+t0n/BWPFtv7WWCN5Yzj0N6FJNUUqBQ==", "cpu": [ "ppc64" ], @@ -124,9 +134,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.4.tgz", - "integrity": "sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.3.tgz", + "integrity": "sha512-PuwVXbnP87Tcff5I9ngV0lmiSu40xw1At6i3GsU77U7cjDDB4s0X2cyFuBiDa1SBk9DnvWwnGvVaGBqoFWPb7A==", "cpu": [ "arm" ], @@ -140,9 +150,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.4.tgz", - "integrity": "sha512-bBy69pgfhMGtCnwpC/x5QhfxAz/cBgQ9enbtwjf6V9lnPI/hMyT9iWpR1arm0l3kttTr4L0KSLpKmLp/ilKS9A==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.3.tgz", + "integrity": "sha512-XelR6MzjlZuBM4f5z2IQHK6LkK34Cvv6Rj2EntER3lwCBFdg6h2lKbtRjpTTsdEjD/WSe1q8UyPBXP1x3i/wYQ==", "cpu": [ "arm64" ], @@ -156,9 +166,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.4.tgz", - "integrity": "sha512-TVhdVtQIFuVpIIR282btcGC2oGQoSfZfmBdTip2anCaVYcqWlZXGcdcKIUklfX2wj0JklNYgz39OBqh2cqXvcQ==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.3.tgz", + "integrity": "sha512-ogtTpYHT/g1GWS/zKM0cc/tIebFjm1F9Aw1boQ2Y0eUQ+J89d0jFY//s9ei9jVIlkYi8AfOjiixcLJSGNSOAdQ==", "cpu": [ "x64" ], @@ -172,9 +182,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.4.tgz", - "integrity": "sha512-Y1giCfM4nlHDWEfSckMzeWNdQS31BQGs9/rouw6Ub91tkK79aIMTH3q9xHvzH8d0wDru5Ci0kWB8b3up/nl16g==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.3.tgz", + "integrity": "sha512-eESK5yfPNTqpAmDfFWNsOhmIOaQA59tAcF/EfYvo5/QWQCzXn5iUSOnqt3ra3UdzBv073ykTtmeLJZGt3HhA+w==", "cpu": [ "arm64" ], @@ -188,9 +198,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.4.tgz", - "integrity": "sha512-CJsry8ZGM5VFVeyUYB3cdKpd/H69PYez4eJh1W/t38vzutdjEjtP7hB6eLKBoOdxcAlCtEYHzQ/PJ/oU9I4u0A==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.3.tgz", + "integrity": "sha512-Kd8glo7sIZtwOLcPbW0yLpKmBNWMANZhrC1r6K++uDR2zyzb6AeOYtI6udbtabmQpFaxJ8uduXMAo1gs5ozz8A==", "cpu": [ "x64" ], @@ -204,9 +214,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.4.tgz", - "integrity": "sha512-yYq+39NlTRzU2XmoPW4l5Ifpl9fqSk0nAJYM/V/WUGPEFfek1epLHJIkTQM6bBs1swApjO5nWgvr843g6TjxuQ==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.3.tgz", + "integrity": "sha512-EJiyS70BYybOBpJth3M0KLOus0n+RRMKTYzhYhFeMwp7e/RaajXvP+BWlmEXNk6uk+KAu46j/kaQzr6au+JcIw==", "cpu": [ "arm64" ], @@ -220,9 +230,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.4.tgz", - "integrity": "sha512-0FgvOJ6UUMflsHSPLzdfDnnBBVoCDtBTVyn/MrWloUNvq/5SFmh13l3dvgRPkDihRxb77Y17MbqbCAa2strMQQ==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.3.tgz", + "integrity": "sha512-Q+wSjaLpGxYf7zC0kL0nDlhsfuFkoN+EXrx2KSB33RhinWzejOd6AvgmP5JbkgXKmjhmpfgKZq24pneodYqE8Q==", "cpu": [ "x64" ], @@ -236,9 +246,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.4.tgz", - "integrity": "sha512-kro4c0P85GMfFYqW4TWOpvmF8rFShbWGnrLqlzp4X1TNWjRY3JMYUfDCtOxPKOIY8B0WC8HN51hGP4I4hz4AaQ==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.3.tgz", + "integrity": "sha512-dUOVmAUzuHy2ZOKIHIKHCm58HKzFqd+puLaS424h6I85GlSDRZIA5ycBixb3mFgM0Jdh+ZOSB6KptX30DD8YOQ==", "cpu": [ "arm" ], @@ -252,9 +262,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.4.tgz", - "integrity": "sha512-+89UsQTfXdmjIvZS6nUnOOLoXnkUTB9hR5QAeLrQdzOSWZvNSAXAtcRDHWtqAUtAmv7ZM1WPOOeSxDzzzMogiQ==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.3.tgz", + "integrity": "sha512-xCUgnNYhRD5bb1C1nqrDV1PfkwgbswTTBRbAd8aH5PhYzikdf/ddtsYyMXFfGSsb/6t6QaPSzxtbfAZr9uox4A==", "cpu": [ "arm64" ], @@ -268,9 +278,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.4.tgz", - "integrity": "sha512-yTEjoapy8UP3rv8dB0ip3AfMpRbyhSN3+hY8mo/i4QXFeDxmiYbEKp3ZRjBKcOP862Ua4b1PDfwlvbuwY7hIGQ==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.3.tgz", + "integrity": "sha512-yplPOpczHOO4jTYKmuYuANI3WhvIPSVANGcNUeMlxH4twz/TeXuzEP41tGKNGWJjuMhotpGabeFYGAOU2ummBw==", "cpu": [ "ia32" ], @@ -284,9 +294,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.4.tgz", - "integrity": "sha512-NeqqYkrcGzFwi6CGRGNMOjWGGSYOpqwCjS9fvaUlX5s3zwOtn1qwg1s2iE2svBe4Q/YOG1q6875lcAoQK/F4VA==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.3.tgz", + "integrity": "sha512-P4BLP5/fjyihmXCELRGrLd793q/lBtKMQl8ARGpDxgzgIKJDRJ/u4r1A/HgpBpKpKZelGct2PGI4T+axcedf6g==", "cpu": [ "loong64" ], @@ -300,9 +310,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.4.tgz", - "integrity": "sha512-IcvTlF9dtLrfL/M8WgNI/qJYBENP3ekgsHbYUIzEzq5XJzzVEV/fXY9WFPfEEXmu3ck2qJP8LG/p3Q8f7Zc2Xg==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.3.tgz", + "integrity": "sha512-eRAOV2ODpu6P5divMEMa26RRqb2yUoYsuQQOuFUexUoQndm4MdpXXDBbUoKIc0iPa4aCO7gIhtnYomkn2x+bag==", "cpu": [ "mips64el" ], @@ -316,9 +326,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.4.tgz", - "integrity": "sha512-HOy0aLTJTVtoTeGZh4HSXaO6M95qu4k5lJcH4gxv56iaycfz1S8GO/5Jh6X4Y1YiI0h7cRyLi+HixMR+88swag==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.3.tgz", + "integrity": "sha512-ZC4jV2p7VbzTlnl8nZKLcBkfzIf4Yad1SJM4ZMKYnJqZFD4rTI+pBG65u8ev4jk3/MPwY9DvGn50wi3uhdaghg==", "cpu": [ "ppc64" ], @@ -332,9 +342,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.4.tgz", - "integrity": "sha512-i8JUDAufpz9jOzo4yIShCTcXzS07vEgWzyX3NH2G7LEFVgrLEhjwL3ajFE4fZI3I4ZgiM7JH3GQ7ReObROvSUA==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.3.tgz", + "integrity": "sha512-LDDODcFzNtECTrUUbVCs6j9/bDVqy7DDRsuIXJg6so+mFksgwG7ZVnTruYi5V+z3eE5y+BJZw7VvUadkbfg7QA==", "cpu": [ "riscv64" ], @@ -348,9 +358,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.4.tgz", - "integrity": "sha512-jFnu+6UbLlzIjPQpWCNh5QtrcNfMLjgIavnwPQAfoGx4q17ocOU9MsQ2QVvFxwQoWpZT8DvTLooTvmOQXkO51g==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.3.tgz", + "integrity": "sha512-s+w/NOY2k0yC2p9SLen+ymflgcpRkvwwa02fqmAwhBRI3SC12uiS10edHHXlVWwfAagYSY5UpmT/zISXPMW3tQ==", "cpu": [ "s390x" ], @@ -364,9 +374,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.4.tgz", - "integrity": "sha512-6e0cvXwzOnVWJHq+mskP8DNSrKBr1bULBvnFLpc1KY+d+irZSgZ02TGse5FsafKS5jg2e4pbvK6TPXaF/A6+CA==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.3.tgz", + "integrity": "sha512-nQHDz4pXjSDC6UfOE1Fw9Q8d6GCAd9KdvMZpfVGWSJztYCarRgSDfOVBY5xwhQXseiyxapkiSJi/5/ja8mRFFA==", "cpu": [ "x64" ], @@ -380,9 +390,9 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.4.tgz", - "integrity": "sha512-vUnkBYxZW4hL/ie91hSqaSNjulOnYXE1VSLusnvHg2u3jewJBz3YzB9+oCw8DABeVqZGg94t9tyZFoHma8gWZQ==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.3.tgz", + "integrity": "sha512-1QaLtOWq0mzK6tzzp0jRN3eccmN3hezey7mhLnzC6oNlJoUJz4nym5ZD7mDnS/LZQgkrhEbEiTn515lPeLpgWA==", "cpu": [ "arm64" ], @@ -396,9 +406,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.4.tgz", - "integrity": "sha512-XAg8pIQn5CzhOB8odIcAm42QsOfa98SBeKUdo4xa8OvX8LbMZqEtgeWE9P/Wxt7MlG2QqvjGths+nq48TrUiKw==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.3.tgz", + "integrity": "sha512-i5Hm68HXHdgv8wkrt+10Bc50zM0/eonPb/a/OFVfB6Qvpiirco5gBA5bz7S2SHuU+Y4LWn/zehzNX14Sp4r27g==", "cpu": [ "x64" ], @@ -412,9 +422,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.4.tgz", - "integrity": "sha512-Ct2WcFEANlFDtp1nVAXSNBPDxyU+j7+tId//iHXU2f/lN5AmO4zLyhDcpR5Cz1r08mVxzt3Jpyt4PmXQ1O6+7A==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.3.tgz", + "integrity": "sha512-zGAVApJEYTbOC6H/3QBr2mq3upG/LBEXr85/pTtKiv2IXcgKV0RT0QA/hSXZqSvLEpXeIxah7LczB4lkiYhTAQ==", "cpu": [ "arm64" ], @@ -428,9 +438,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.4.tgz", - "integrity": "sha512-xAGGhyOQ9Otm1Xu8NT1ifGLnA6M3sJxZ6ixylb+vIUVzvvd6GOALpwQrYrtlPouMqd/vSbgehz6HaVk4+7Afhw==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.3.tgz", + "integrity": "sha512-fpqctI45NnCIDKBH5AXQBsD0NDPbEFczK98hk/aa6HJxbl+UtLkJV2+Bvy5hLSLk3LHmqt0NTkKNso1A9y1a4w==", "cpu": [ "x64" ], @@ -444,9 +454,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.4.tgz", - "integrity": "sha512-Mw+tzy4pp6wZEK0+Lwr76pWLjrtjmJyUB23tHKqEDP74R3q95luY/bXqXZeYl4NYlvwOqoRKlInQialgCKy67Q==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.3.tgz", + "integrity": "sha512-ROJhm7d8bk9dMCUZjkS8fgzsPAZEjtRJqCAmVgB0gMrvG7hfmPmz9k1rwO4jSiblFjYmNvbECL9uhaPzONMfgA==", "cpu": [ "x64" ], @@ -460,9 +470,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.4.tgz", - "integrity": "sha512-AVUP428VQTSddguz9dO9ngb+E5aScyg7nOeJDrF1HPYu555gmza3bDGMPhmVXL8svDSoqPCsCPjb265yG/kLKQ==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.3.tgz", + "integrity": "sha512-YWcow8peiHpNBiIXHwaswPnAXLsLVygFwCB3A7Bh5jRkIBFWHGmNQ48AlX4xDvQNoMZlPYzjVOQDYEzWCqufMQ==", "cpu": [ "arm64" ], @@ -476,9 +486,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.4.tgz", - "integrity": "sha512-i1sW+1i+oWvQzSgfRcxxG2k4I9n3O9NRqy8U+uugaT2Dy7kLO9Y7wI72haOahxceMX8hZAzgGou1FhndRldxRg==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.3.tgz", + "integrity": "sha512-qspTZOIGoXVS4DpNqUYUs9UxVb04khS1Degaw/MnfMe7goQ3lTfQ13Vw4qY/Nj0979BGvMRpAYbs/BAxEvU8ew==", "cpu": [ "ia32" ], @@ -492,9 +502,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.4.tgz", - "integrity": "sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.3.tgz", + "integrity": "sha512-ICgUR+kPimx0vvRzf+N/7L7tVSQeE3BYY+NhHRHXS1kBuPO7z2+7ea2HbhDyZdTephgvNvKrlDDKUexuCVBVvg==", "cpu": [ "x64" ], @@ -511,6 +521,7 @@ "version": "2.1.12", "resolved": "https://registry.npmjs.org/@jscad/3mf-serializer/-/3mf-serializer-2.1.12.tgz", "integrity": "sha512-+rxAIKIHCpaplupwwsdXtG1IdimPXFFB45nrjy6gdFHi36bEQW6y/RQD/ngenRiKnYSxu7/M0LatHcjve8z64A==", + "license": "MIT", "dependencies": { "@jscad/array-utils": "2.1.4", "@jscad/modeling": "2.12.3", @@ -521,12 +532,14 @@ "node_modules/@jscad/array-utils": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/@jscad/array-utils/-/array-utils-2.1.4.tgz", - "integrity": "sha512-c31r4zSKsE+4Xfwk2V8monDA0hx5G89QGzaakWVUvuGNowYS9WSsYCwHiTIXodjR+HEnDu4okQ7k/whmP0Ne2g==" + "integrity": "sha512-c31r4zSKsE+4Xfwk2V8monDA0hx5G89QGzaakWVUvuGNowYS9WSsYCwHiTIXodjR+HEnDu4okQ7k/whmP0Ne2g==", + "license": "MIT" }, "node_modules/@jscad/dxf-serializer": { "version": "2.1.18", "resolved": "https://registry.npmjs.org/@jscad/dxf-serializer/-/dxf-serializer-2.1.18.tgz", "integrity": "sha512-T5Qe2jbEphcWAk7GaOY8PCMD4DPhTm6gWk/MPJCExphhnUwJqcU/1RiMb5hiD+N6hHzmlxD59I8QTjlp9LbLSA==", + "license": "MIT", "dependencies": { "@jscad/array-utils": "2.1.4", "@jscad/modeling": "2.12.3" @@ -535,17 +548,20 @@ "node_modules/@jscad/io-utils": { "version": "2.0.28", "resolved": "https://registry.npmjs.org/@jscad/io-utils/-/io-utils-2.0.28.tgz", - "integrity": "sha512-spXh37wAgmwjKztoH/HANLgImcqRHX5+H/cRIxPfpqDIWvu7I5bRg2ZTwh25SYlKIzxPk4qX5Nu7Ax5+Kg+QXQ==" + "integrity": "sha512-spXh37wAgmwjKztoH/HANLgImcqRHX5+H/cRIxPfpqDIWvu7I5bRg2ZTwh25SYlKIzxPk4qX5Nu7Ax5+Kg+QXQ==", + "license": "MIT" }, "node_modules/@jscad/modeling": { "version": "2.12.3", "resolved": "https://registry.npmjs.org/@jscad/modeling/-/modeling-2.12.3.tgz", - "integrity": "sha512-DnAacXq3zhlYWIixGlFD7RMpgZAMuCaMZNQov0NaoFfs2GaBuTC5eqkqKcEVbhEerBmTllbjjF5IXjJMt9jcOA==" + "integrity": "sha512-DnAacXq3zhlYWIixGlFD7RMpgZAMuCaMZNQov0NaoFfs2GaBuTC5eqkqKcEVbhEerBmTllbjjF5IXjJMt9jcOA==", + "license": "MIT" }, "node_modules/@jscad/stl-serializer": { "version": "2.1.18", "resolved": "https://registry.npmjs.org/@jscad/stl-serializer/-/stl-serializer-2.1.18.tgz", "integrity": "sha512-pz++TRjHI7jBPnnxQUi4B/uYUG3yCDsKlw8+xL2kumwjb+auc6Ng6Rnr/GqUTkgHrnGut08wg/8AekyWjvBwYg==", + "license": "MIT", "dependencies": { "@jscad/array-utils": "2.1.4", "@jscad/modeling": "2.12.3" @@ -555,6 +571,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/@jsep-plugin/assignment/-/assignment-1.3.0.tgz", "integrity": "sha512-VVgV+CXrhbMI3aSusQyclHkenWSAm95WaiKrMxRFam3JSUiIaQjoMIw2sEs/OX4XifnqeQUN4DYbJjlA8EfktQ==", + "license": "MIT", "engines": { "node": ">= 10.16.0" }, @@ -566,6 +583,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/@jsep-plugin/regex/-/regex-1.0.4.tgz", "integrity": "sha512-q7qL4Mgjs1vByCaTnDFcBnV9HS7GVPJX5vyVoCgZHNSC9rjwIlmbXG5sUuorR5ndfHAIlJ8pVStxvjXHbNvtUg==", + "license": "MIT", "engines": { "node": ">= 10.16.0" }, @@ -574,9 +592,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.41.0.tgz", - "integrity": "sha512-KxN+zCjOYHGwCl4UCtSfZ6jrq/qi88JDUtiEFk8LELEHq2Egfc/FgW+jItZiOLRuQfb/3xJSgFuNPC9jzggX+A==", + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.40.1.tgz", + "integrity": "sha512-kxz0YeeCrRUHz3zyqvd7n+TVRlNyTifBsmnmNPtk3hQURUyG9eAB+usz6DAwagMusjx/zb3AjvDUvhFGDAexGw==", "cpu": [ "arm" ], @@ -587,9 +605,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.41.0.tgz", - "integrity": "sha512-yDvqx3lWlcugozax3DItKJI5j05B0d4Kvnjx+5mwiUpWramVvmAByYigMplaoAQ3pvdprGCTCE03eduqE/8mPQ==", + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.40.1.tgz", + "integrity": "sha512-PPkxTOisoNC6TpnDKatjKkjRMsdaWIhyuMkA4UsBXT9WEZY4uHezBTjs6Vl4PbqQQeu6oION1w2voYZv9yquCw==", "cpu": [ "arm64" ], @@ -600,9 +618,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.41.0.tgz", - "integrity": "sha512-2KOU574vD3gzcPSjxO0eyR5iWlnxxtmW1F5CkNOHmMlueKNCQkxR6+ekgWyVnz6zaZihpUNkGxjsYrkTJKhkaw==", + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.40.1.tgz", + "integrity": "sha512-VWXGISWFY18v/0JyNUy4A46KCFCb9NVsH+1100XP31lud+TzlezBbz24CYzbnA4x6w4hx+NYCXDfnvDVO6lcAA==", "cpu": [ "arm64" ], @@ -613,9 +631,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.41.0.tgz", - "integrity": "sha512-gE5ACNSxHcEZyP2BA9TuTakfZvULEW4YAOtxl/A/YDbIir/wPKukde0BNPlnBiP88ecaN4BJI2TtAd+HKuZPQQ==", + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.40.1.tgz", + "integrity": "sha512-nIwkXafAI1/QCS7pxSpv/ZtFW6TXcNUEHAIA9EIyw5OzxJZQ1YDrX+CL6JAIQgZ33CInl1R6mHet9Y/UZTg2Bw==", "cpu": [ "x64" ], @@ -626,9 +644,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.41.0.tgz", - "integrity": "sha512-GSxU6r5HnWij7FoSo7cZg3l5GPg4HFLkzsFFh0N/b16q5buW1NAWuCJ+HMtIdUEi6XF0qH+hN0TEd78laRp7Dg==", + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.40.1.tgz", + "integrity": "sha512-BdrLJ2mHTrIYdaS2I99mriyJfGGenSaP+UwGi1kB9BLOCu9SR8ZpbkmmalKIALnRw24kM7qCN0IOm6L0S44iWw==", "cpu": [ "arm64" ], @@ -639,9 +657,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.41.0.tgz", - "integrity": "sha512-KGiGKGDg8qLRyOWmk6IeiHJzsN/OYxO6nSbT0Vj4MwjS2XQy/5emsmtoqLAabqrohbgLWJ5GV3s/ljdrIr8Qjg==", + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.40.1.tgz", + "integrity": "sha512-VXeo/puqvCG8JBPNZXZf5Dqq7BzElNJzHRRw3vjBE27WujdzuOPecDPc/+1DcdcTptNBep3861jNq0mYkT8Z6Q==", "cpu": [ "x64" ], @@ -652,9 +670,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.41.0.tgz", - "integrity": "sha512-46OzWeqEVQyX3N2/QdiU/CMXYDH/lSHpgfBkuhl3igpZiaB3ZIfSjKuOnybFVBQzjsLwkus2mjaESy8H41SzvA==", + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.40.1.tgz", + "integrity": "sha512-ehSKrewwsESPt1TgSE/na9nIhWCosfGSFqv7vwEtjyAqZcvbGIg4JAcV7ZEh2tfj/IlfBeZjgOXm35iOOjadcg==", "cpu": [ "arm" ], @@ -665,9 +683,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.41.0.tgz", - "integrity": "sha512-lfgW3KtQP4YauqdPpcUZHPcqQXmTmH4nYU0cplNeW583CMkAGjtImw4PKli09NFi2iQgChk4e9erkwlfYem6Lg==", + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.40.1.tgz", + "integrity": "sha512-m39iO/aaurh5FVIu/F4/Zsl8xppd76S4qoID8E+dSRQvTyZTOI2gVk3T4oqzfq1PtcvOfAVlwLMK3KRQMaR8lg==", "cpu": [ "arm" ], @@ -678,9 +696,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.41.0.tgz", - "integrity": "sha512-nn8mEyzMbdEJzT7cwxgObuwviMx6kPRxzYiOl6o/o+ChQq23gfdlZcUNnt89lPhhz3BYsZ72rp0rxNqBSfqlqw==", + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.40.1.tgz", + "integrity": "sha512-Y+GHnGaku4aVLSgrT0uWe2o2Rq8te9hi+MwqGF9r9ORgXhmHK5Q71N757u0F8yU1OIwUIFy6YiJtKjtyktk5hg==", "cpu": [ "arm64" ], @@ -691,9 +709,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.41.0.tgz", - "integrity": "sha512-l+QK99je2zUKGd31Gh+45c4pGDAqZSuWQiuRFCdHYC2CSiO47qUWsCcenrI6p22hvHZrDje9QjwSMAFL3iwXwQ==", + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.40.1.tgz", + "integrity": "sha512-jEwjn3jCA+tQGswK3aEWcD09/7M5wGwc6+flhva7dsQNRZZTe30vkalgIzV4tjkopsTS9Jd7Y1Bsj6a4lzz8gQ==", "cpu": [ "arm64" ], @@ -704,9 +722,9 @@ ] }, "node_modules/@rollup/rollup-linux-loongarch64-gnu": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.41.0.tgz", - "integrity": "sha512-WbnJaxPv1gPIm6S8O/Wg+wfE/OzGSXlBMbOe4ie+zMyykMOeqmgD1BhPxZQuDqwUN+0T/xOFtL2RUWBspnZj3w==", + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.40.1.tgz", + "integrity": "sha512-ySyWikVhNzv+BV/IDCsrraOAZ3UaC8SZB67FZlqVwXwnFhPihOso9rPOxzZbjp81suB1O2Topw+6Ug3JNegejQ==", "cpu": [ "loong64" ], @@ -717,9 +735,9 @@ ] }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.41.0.tgz", - "integrity": "sha512-eRDWR5t67/b2g8Q/S8XPi0YdbKcCs4WQ8vklNnUYLaSWF+Cbv2axZsp4jni6/j7eKvMLYCYdcsv8dcU+a6QNFg==", + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.40.1.tgz", + "integrity": "sha512-BvvA64QxZlh7WZWqDPPdt0GH4bznuL6uOO1pmgPnnv86rpUpc8ZxgZwcEgXvo02GRIZX1hQ0j0pAnhwkhwPqWg==", "cpu": [ "ppc64" ], @@ -730,9 +748,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.41.0.tgz", - "integrity": "sha512-TWrZb6GF5jsEKG7T1IHwlLMDRy2f3DPqYldmIhnA2DVqvvhY2Ai184vZGgahRrg8k9UBWoSlHv+suRfTN7Ua4A==", + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.40.1.tgz", + "integrity": "sha512-EQSP+8+1VuSulm9RKSMKitTav89fKbHymTf25n5+Yr6gAPZxYWpj3DzAsQqoaHAk9YX2lwEyAf9S4W8F4l3VBQ==", "cpu": [ "riscv64" ], @@ -743,9 +761,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.41.0.tgz", - "integrity": "sha512-ieQljaZKuJpmWvd8gW87ZmSFwid6AxMDk5bhONJ57U8zT77zpZ/TPKkU9HpnnFrM4zsgr4kiGuzbIbZTGi7u9A==", + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.40.1.tgz", + "integrity": "sha512-n/vQ4xRZXKuIpqukkMXZt9RWdl+2zgGNx7Uda8NtmLJ06NL8jiHxUawbwC+hdSq1rrw/9CghCpEONor+l1e2gA==", "cpu": [ "riscv64" ], @@ -756,9 +774,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.41.0.tgz", - "integrity": "sha512-/L3pW48SxrWAlVsKCN0dGLB2bi8Nv8pr5S5ocSM+S0XCn5RCVCXqi8GVtHFsOBBCSeR+u9brV2zno5+mg3S4Aw==", + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.40.1.tgz", + "integrity": "sha512-h8d28xzYb98fMQKUz0w2fMc1XuGzLLjdyxVIbhbil4ELfk5/orZlSTpF/xdI9C8K0I8lCkq+1En2RJsawZekkg==", "cpu": [ "s390x" ], @@ -769,9 +787,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.41.0.tgz", - "integrity": "sha512-XMLeKjyH8NsEDCRptf6LO8lJk23o9wvB+dJwcXMaH6ZQbbkHu2dbGIUindbMtRN6ux1xKi16iXWu6q9mu7gDhQ==", + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.40.1.tgz", + "integrity": "sha512-XiK5z70PEFEFqcNj3/zRSz/qX4bp4QIraTy9QjwJAb/Z8GM7kVUsD0Uk8maIPeTyPCP03ChdI+VVmJriKYbRHQ==", "cpu": [ "x64" ], @@ -782,9 +800,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.41.0.tgz", - "integrity": "sha512-m/P7LycHZTvSQeXhFmgmdqEiTqSV80zn6xHaQ1JSqwCtD1YGtwEK515Qmy9DcB2HK4dOUVypQxvhVSy06cJPEg==", + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.40.1.tgz", + "integrity": "sha512-2BRORitq5rQ4Da9blVovzNCMaUlyKrzMSvkVR0D4qPuOy/+pMCrh1d7o01RATwVy+6Fa1WBw+da7QPeLWU/1mQ==", "cpu": [ "x64" ], @@ -795,9 +813,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.41.0.tgz", - "integrity": "sha512-4yodtcOrFHpbomJGVEqZ8fzD4kfBeCbpsUy5Pqk4RluXOdsWdjLnjhiKy2w3qzcASWd04fp52Xz7JKarVJ5BTg==", + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.40.1.tgz", + "integrity": "sha512-b2bcNm9Kbde03H+q+Jjw9tSfhYkzrDUf2d5MAd1bOJuVplXvFhWz7tRtWvD8/ORZi7qSCy0idW6tf2HgxSXQSg==", "cpu": [ "arm64" ], @@ -808,9 +826,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.41.0.tgz", - "integrity": "sha512-tmazCrAsKzdkXssEc65zIE1oC6xPHwfy9d5Ta25SRCDOZS+I6RypVVShWALNuU9bxIfGA0aqrmzlzoM5wO5SPQ==", + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.40.1.tgz", + "integrity": "sha512-DfcogW8N7Zg7llVEfpqWMZcaErKfsj9VvmfSyRjCyo4BI3wPEfrzTtJkZG6gKP/Z92wFm6rz2aDO7/JfiR/whA==", "cpu": [ "ia32" ], @@ -821,9 +839,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.41.0.tgz", - "integrity": "sha512-h1J+Yzjo/X+0EAvR2kIXJDuTuyT7drc+t2ALY0nIcGPbTatNOf0VWdhEA2Z4AAjv6X1NJV7SYo5oCTYRJhSlVA==", + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.40.1.tgz", + "integrity": "sha512-ECyOuDeH3C1I8jH2MK1RtBJW+YPMvSfT0a5NN0nHfQYnDSJ6tUiZH3gzwVP5/Kfh/+Tt7tpWVF9LXNTnhTJ3kA==", "cpu": [ "x64" ], @@ -837,7 +855,8 @@ "version": "23.1.3", "resolved": "https://registry.npmjs.org/@tweenjs/tween.js/-/tween.js-23.1.3.tgz", "integrity": "sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/estree": { "version": "1.0.7", @@ -846,16 +865,18 @@ "dev": true }, "node_modules/@types/stats.js": { - "version": "0.17.4", - "resolved": "https://registry.npmjs.org/@types/stats.js/-/stats.js-0.17.4.tgz", - "integrity": "sha512-jIBvWWShCvlBqBNIZt0KAshWpvSjhkwkEu4ZUcASoAvhmrgAUI2t1dXrjSL4xXVLB4FznPrIsX3nKXFl/Dt4vA==", - "dev": true + "version": "0.17.3", + "resolved": "https://registry.npmjs.org/@types/stats.js/-/stats.js-0.17.3.tgz", + "integrity": "sha512-pXNfAD3KHOdif9EQXZ9deK82HVNaXP5ZIF5RP2QG6OQFNTaY2YIetfrE9t528vEreGQvEPRDDc8muaoYeK0SxQ==", + "dev": true, + "license": "MIT" }, "node_modules/@types/three": { "version": "0.176.0", "resolved": "https://registry.npmjs.org/@types/three/-/three-0.176.0.tgz", "integrity": "sha512-FwfPXxCqOtP7EdYMagCFePNKoG1AGBDUEVKtluv2BTVRpSt7b+X27xNsirPCTCqY1pGYsPUzaM3jgWP7dXSxlw==", "dev": true, + "license": "MIT", "dependencies": { "@dimforge/rapier3d-compat": "^0.12.0", "@tweenjs/tween.js": "~23.1.3", @@ -870,33 +891,37 @@ "version": "0.8.2", "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz", "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/webxr": { "version": "0.5.22", "resolved": "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.22.tgz", "integrity": "sha512-Vr6Stjv5jPRqH690f5I5GLjVk8GSsoQSYJ2FVd/3jJF7KaqfwPi3ehfBS96mlQ2kPCwZaX6U0rG2+NGHBKkA/A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@webgpu/types": { "version": "0.1.60", "resolved": "https://registry.npmjs.org/@webgpu/types/-/types-0.1.60.tgz", "integrity": "sha512-8B/tdfRFKdrnejqmvq95ogp8tf52oZ51p3f4QD5m5Paey/qlX4Rhhy5Y8tgFMi7Ms70HzcMMw3EQjH/jdhTwlA==", - "dev": true + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/bindings": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "license": "MIT", "optional": true, "dependencies": { "file-uri-to-path": "1.0.0" } }, "node_modules/esbuild": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.4.tgz", - "integrity": "sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.3.tgz", + "integrity": "sha512-qKA6Pvai73+M2FtftpNKRxJ78GIjmFXFxd/1DVBqGo/qNhLSfv+G12n9pNoWdytJC8U00TrViOwpjT0zgqQS8Q==", "dev": true, "hasInstallScript": true, "bin": { @@ -906,31 +931,31 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.4", - "@esbuild/android-arm": "0.25.4", - "@esbuild/android-arm64": "0.25.4", - "@esbuild/android-x64": "0.25.4", - "@esbuild/darwin-arm64": "0.25.4", - "@esbuild/darwin-x64": "0.25.4", - "@esbuild/freebsd-arm64": "0.25.4", - "@esbuild/freebsd-x64": "0.25.4", - "@esbuild/linux-arm": "0.25.4", - "@esbuild/linux-arm64": "0.25.4", - "@esbuild/linux-ia32": "0.25.4", - "@esbuild/linux-loong64": "0.25.4", - "@esbuild/linux-mips64el": "0.25.4", - "@esbuild/linux-ppc64": "0.25.4", - "@esbuild/linux-riscv64": "0.25.4", - "@esbuild/linux-s390x": "0.25.4", - "@esbuild/linux-x64": "0.25.4", - "@esbuild/netbsd-arm64": "0.25.4", - "@esbuild/netbsd-x64": "0.25.4", - "@esbuild/openbsd-arm64": "0.25.4", - "@esbuild/openbsd-x64": "0.25.4", - "@esbuild/sunos-x64": "0.25.4", - "@esbuild/win32-arm64": "0.25.4", - "@esbuild/win32-ia32": "0.25.4", - "@esbuild/win32-x64": "0.25.4" + "@esbuild/aix-ppc64": "0.25.3", + "@esbuild/android-arm": "0.25.3", + "@esbuild/android-arm64": "0.25.3", + "@esbuild/android-x64": "0.25.3", + "@esbuild/darwin-arm64": "0.25.3", + "@esbuild/darwin-x64": "0.25.3", + "@esbuild/freebsd-arm64": "0.25.3", + "@esbuild/freebsd-x64": "0.25.3", + "@esbuild/linux-arm": "0.25.3", + "@esbuild/linux-arm64": "0.25.3", + "@esbuild/linux-ia32": "0.25.3", + "@esbuild/linux-loong64": "0.25.3", + "@esbuild/linux-mips64el": "0.25.3", + "@esbuild/linux-ppc64": "0.25.3", + "@esbuild/linux-riscv64": "0.25.3", + "@esbuild/linux-s390x": "0.25.3", + "@esbuild/linux-x64": "0.25.3", + "@esbuild/netbsd-arm64": "0.25.3", + "@esbuild/netbsd-x64": "0.25.3", + "@esbuild/openbsd-arm64": "0.25.3", + "@esbuild/openbsd-x64": "0.25.3", + "@esbuild/sunos-x64": "0.25.3", + "@esbuild/win32-arm64": "0.25.3", + "@esbuild/win32-ia32": "0.25.3", + "@esbuild/win32-x64": "0.25.3" } }, "node_modules/fdir": { @@ -950,12 +975,14 @@ "node_modules/fflate": { "version": "0.7.3", "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.7.3.tgz", - "integrity": "sha512-0Zz1jOzJWERhyhsimS54VTqOteCNwRtIlh8isdL0AXLo0g7xNTfTL7oWrkmCnPhZGocKIkWHBistBrrpoNH3aw==" + "integrity": "sha512-0Zz1jOzJWERhyhsimS54VTqOteCNwRtIlh8isdL0AXLo0g7xNTfTL7oWrkmCnPhZGocKIkWHBistBrrpoNH3aw==", + "license": "MIT" }, "node_modules/file-uri-to-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "license": "MIT", "optional": true }, "node_modules/fsevents": { @@ -976,6 +1003,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/jsep/-/jsep-1.4.0.tgz", "integrity": "sha512-B7qPcEVE3NVkmSJbaYxvv4cHkVW7DQsZz13pUMrfS8z8Q/BuShN+gcTXrUlPiGqM2/t/EEaI030bpxMqY8gMlw==", + "license": "MIT", "engines": { "node": ">= 10.16.0" } @@ -984,6 +1012,7 @@ "version": "10.1.0", "resolved": "https://registry.npmjs.org/jsonpath-plus/-/jsonpath-plus-10.1.0.tgz", "integrity": "sha512-gHfV1IYqH8uJHYVTs8BJX1XKy2/rR93+f8QQi0xhx95aCiXn1ettYAd5T+7FU6wfqyDoX/wy0pm/fL3jOKJ9Lg==", + "license": "MIT", "dependencies": { "@jsep-plugin/assignment": "^1.2.1", "@jsep-plugin/regex": "^1.0.3", @@ -1000,23 +1029,27 @@ "node_modules/lil-gui": { "version": "0.20.0", "resolved": "https://registry.npmjs.org/lil-gui/-/lil-gui-0.20.0.tgz", - "integrity": "sha512-k7Ipr0ztqslMA2XvM5z5ZaWhxQtnEOwJBfI/hmSuRh6q4iMG9L0boqqrnZSzBR1jzyJ28OMl47l65ILzRe1TdA==" + "integrity": "sha512-k7Ipr0ztqslMA2XvM5z5ZaWhxQtnEOwJBfI/hmSuRh6q4iMG9L0boqqrnZSzBR1jzyJ28OMl47l65ILzRe1TdA==", + "license": "MIT" }, "node_modules/manifold-3d": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/manifold-3d/-/manifold-3d-3.0.0.tgz", - "integrity": "sha512-6XxRf5LH4s7WIlRrvtzLMg+CHio5TznIE0w0PU/Ad8IzD36QLjb64QdSeQp9ISrk4tGtIqVAycevpPe1ExGTKg==" + "integrity": "sha512-6XxRf5LH4s7WIlRrvtzLMg+CHio5TznIE0w0PU/Ad8IzD36QLjb64QdSeQp9ISrk4tGtIqVAycevpPe1ExGTKg==", + "license": "Apache-2.0" }, "node_modules/meshoptimizer": { "version": "0.18.1", "resolved": "https://registry.npmjs.org/meshoptimizer/-/meshoptimizer-0.18.1.tgz", "integrity": "sha512-ZhoIoL7TNV4s5B6+rx5mC//fw8/POGyNxS/DZyCJeiZ12ScLfVwRE/GfsxwiTkMYYD5DmK2/JXnEVXqL4rF+Sw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/nan": { "version": "2.22.2", "resolved": "https://registry.npmjs.org/nan/-/nan-2.22.2.tgz", "integrity": "sha512-DANghxFkS1plDdRsX0X9pm0Z6SJNN6gBdtXfanwoZ8hooC5gosGFSBGRYHUVPz1asKA/kMRqDRdHrluZ61SpBQ==", + "license": "MIT", "optional": true }, "node_modules/nanoid": { @@ -1041,6 +1074,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/onml/-/onml-1.2.0.tgz", "integrity": "sha512-olqYAg18XoHAhm7tK9DdBCOVdts70DGmMgCNLOWyqZokht2utgGSKBB4JHi6pBZpmioAhcYlxK+91L3tsrz+GA==", + "license": "MIT", "dependencies": { "sax": "^1.2.1" } @@ -1092,9 +1126,9 @@ } }, "node_modules/rollup": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.41.0.tgz", - "integrity": "sha512-HqMFpUbWlf/tvcxBFNKnJyzc7Lk+XO3FGc3pbNBLqEbOz0gPLRgcrlS3UF4MfUrVlstOaP/q0kM6GVvi+LrLRg==", + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.40.1.tgz", + "integrity": "sha512-C5VvvgCCyfyotVITIAv+4efVytl5F7wt+/I2i9q9GZcEXW9BP52YYOXC58igUi+LFZVHukErIIqQSWwv/M3WRw==", "dev": true, "dependencies": { "@types/estree": "1.0.7" @@ -1107,26 +1141,26 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.41.0", - "@rollup/rollup-android-arm64": "4.41.0", - "@rollup/rollup-darwin-arm64": "4.41.0", - "@rollup/rollup-darwin-x64": "4.41.0", - "@rollup/rollup-freebsd-arm64": "4.41.0", - "@rollup/rollup-freebsd-x64": "4.41.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.41.0", - "@rollup/rollup-linux-arm-musleabihf": "4.41.0", - "@rollup/rollup-linux-arm64-gnu": "4.41.0", - "@rollup/rollup-linux-arm64-musl": "4.41.0", - "@rollup/rollup-linux-loongarch64-gnu": "4.41.0", - "@rollup/rollup-linux-powerpc64le-gnu": "4.41.0", - "@rollup/rollup-linux-riscv64-gnu": "4.41.0", - "@rollup/rollup-linux-riscv64-musl": "4.41.0", - "@rollup/rollup-linux-s390x-gnu": "4.41.0", - "@rollup/rollup-linux-x64-gnu": "4.41.0", - "@rollup/rollup-linux-x64-musl": "4.41.0", - "@rollup/rollup-win32-arm64-msvc": "4.41.0", - "@rollup/rollup-win32-ia32-msvc": "4.41.0", - "@rollup/rollup-win32-x64-msvc": "4.41.0", + "@rollup/rollup-android-arm-eabi": "4.40.1", + "@rollup/rollup-android-arm64": "4.40.1", + "@rollup/rollup-darwin-arm64": "4.40.1", + "@rollup/rollup-darwin-x64": "4.40.1", + "@rollup/rollup-freebsd-arm64": "4.40.1", + "@rollup/rollup-freebsd-x64": "4.40.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.40.1", + "@rollup/rollup-linux-arm-musleabihf": "4.40.1", + "@rollup/rollup-linux-arm64-gnu": "4.40.1", + "@rollup/rollup-linux-arm64-musl": "4.40.1", + "@rollup/rollup-linux-loongarch64-gnu": "4.40.1", + "@rollup/rollup-linux-powerpc64le-gnu": "4.40.1", + "@rollup/rollup-linux-riscv64-gnu": "4.40.1", + "@rollup/rollup-linux-riscv64-musl": "4.40.1", + "@rollup/rollup-linux-s390x-gnu": "4.40.1", + "@rollup/rollup-linux-x64-gnu": "4.40.1", + "@rollup/rollup-linux-x64-musl": "4.40.1", + "@rollup/rollup-win32-arm64-msvc": "4.40.1", + "@rollup/rollup-win32-ia32-msvc": "4.40.1", + "@rollup/rollup-win32-x64-msvc": "4.40.1", "fsevents": "~2.3.2" } }, @@ -1134,6 +1168,7 @@ "version": "7.5.5", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.5.tgz", "integrity": "sha512-sy+H0pQofO95VDmFLzyaw9xNJU4KTRSwQIGM6+iG3SypAtCiLDzpeG8sJrNCWn2Up9km+KhkvTdbkrdy+yzZdw==", + "license": "Apache-2.0", "dependencies": { "tslib": "^2.1.0" } @@ -1141,7 +1176,8 @@ "node_modules/sax": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", - "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==" + "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==", + "license": "ISC" }, "node_modules/source-map-js": { "version": "1.2.1", @@ -1155,7 +1191,8 @@ "node_modules/three": { "version": "0.176.0", "resolved": "https://registry.npmjs.org/three/-/three-0.176.0.tgz", - "integrity": "sha512-PWRKYWQo23ojf9oZSlRGH8K09q7nRSWx6LY/HF/UUrMdYgN9i1e2OwJYHoQjwc6HF/4lvvYLC5YC1X8UJL2ZpA==" + "integrity": "sha512-PWRKYWQo23ojf9oZSlRGH8K09q7nRSWx6LY/HF/UUrMdYgN9i1e2OwJYHoQjwc6HF/4lvvYLC5YC1X8UJL2ZpA==", + "license": "MIT" }, "node_modules/tinyglobby": { "version": "0.2.13", @@ -1176,7 +1213,8 @@ "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" }, "node_modules/typescript": { "version": "5.8.3", @@ -1195,14 +1233,15 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/verb-nurbs-web/-/verb-nurbs-web-2.1.3.tgz", "integrity": "sha512-2PvI2bx7dn0r3kWtk+JuDIDZ+p7I5Piu8y6/ZNhUVpilOyHKK1nNzLHtgown+dFOmBnKnuAKIMh1xn/5kzrxZA==", + "license": "MIT", "optionalDependencies": { "webworker-threads": "^0.7.12" } }, "node_modules/vite": { - "version": "6.3.5", - "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz", - "integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==", + "version": "6.3.4", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.4.tgz", + "integrity": "sha512-BiReIiMS2fyFqbqNT/Qqt4CVITDU9M9vE+DKcVAsB+ZV0wvTKd+3hMbkpxz1b+NmEDMegpVbisKiAZOnvO92Sw==", "dev": true, "dependencies": { "esbuild": "^0.25.0", @@ -1278,6 +1317,7 @@ "resolved": "https://registry.npmjs.org/webworker-threads/-/webworker-threads-0.7.17.tgz", "integrity": "sha512-Y2w2aXBbDLk9IzTEb9u+MsODC3s4YlGI7g4h0t+1OAwIO8yBI9rQL35ZYlyayiCuWu1dZMH/P7kGU8OwW7YsyA==", "hasInstallScript": true, + "license": "(MIT AND Apache-2.0)", "optional": true, "dependencies": { "bindings": "^1.3.0", @@ -1287,5 +1327,770 @@ "node": ">= 0.10.16" } } + }, + "dependencies": { + "@bitbybit-dev/base": { + "version": "0.20.4", + "resolved": "https://registry.npmjs.org/@bitbybit-dev/base/-/base-0.20.4.tgz", + "integrity": "sha512-yMsOkUFrm9JIGC3Bs49bu1I/gqwQNK8nVO3XgesOpzZvVQOF5OTxCheiQnrqiUw9DiiPuKw1T0gXBMwThzwdOw==" + }, + "@bitbybit-dev/core": { + "version": "0.20.4", + "resolved": "https://registry.npmjs.org/@bitbybit-dev/core/-/core-0.20.4.tgz", + "integrity": "sha512-T2hOHzvI+ikNxQRvhDyk/TeMCBhjZPY+wLmRSbYHiWnNGP5+3GCesZyb672XfEwPIWRH2kBS4vyp9R9fRnJujQ==", + "requires": { + "@bitbybit-dev/base": "0.20.4", + "@bitbybit-dev/jscad-worker": "0.20.4", + "@bitbybit-dev/manifold-worker": "0.20.4", + "@bitbybit-dev/occt-worker": "0.20.4", + "jsonpath-plus": "10.1.0", + "rxjs": "7.5.5", + "verb-nurbs-web": "2.1.3" + } + }, + "@bitbybit-dev/jscad": { + "version": "0.20.4", + "resolved": "https://registry.npmjs.org/@bitbybit-dev/jscad/-/jscad-0.20.4.tgz", + "integrity": "sha512-e7/7Ag796rwn58H6Nu0lzhDkim+rJTqMWCqFZquNswoX2qqZXCv8azyOFE2LqfTvyIsEeJr/VEWIy2nvmtJnmg==", + "requires": { + "@bitbybit-dev/base": "0.20.4", + "@jscad/3mf-serializer": "2.1.12", + "@jscad/dxf-serializer": "2.1.18", + "@jscad/io-utils": "2.0.28", + "@jscad/modeling": "2.12.3", + "@jscad/stl-serializer": "2.1.18" + } + }, + "@bitbybit-dev/jscad-worker": { + "version": "0.20.4", + "resolved": "https://registry.npmjs.org/@bitbybit-dev/jscad-worker/-/jscad-worker-0.20.4.tgz", + "integrity": "sha512-DsjL2YO6urR8B/8LKYRrk4q9hAJE8oB+e5m+LDDBXbl7Vl0CHdC5ogPm6w07RcAHdSbMJouf2Ow7nGP/oOcjEg==", + "requires": { + "@bitbybit-dev/jscad": "0.20.4", + "rxjs": "7.5.5" + } + }, + "@bitbybit-dev/manifold": { + "version": "0.20.4", + "resolved": "https://registry.npmjs.org/@bitbybit-dev/manifold/-/manifold-0.20.4.tgz", + "integrity": "sha512-rEGO8wOd/RUWPIRWdyE70w79JXhQ1iV6mACBuOH8/UD7+vf9wkk3KLWAYCzVPJP1nvx4+/SKCvU7e1JxEzq0Qw==", + "requires": { + "manifold-3d": "3.0.0" + } + }, + "@bitbybit-dev/manifold-worker": { + "version": "0.20.4", + "resolved": "https://registry.npmjs.org/@bitbybit-dev/manifold-worker/-/manifold-worker-0.20.4.tgz", + "integrity": "sha512-mwU87fg8M3p472dn/RiuveiPtq/IuOWCcoG0uismEE2g+rnciMrCSUSkXMkfXDCk9l0ZqoVfYg+dHVx0KBHBUg==", + "requires": { + "@bitbybit-dev/manifold": "0.20.4", + "rxjs": "7.5.5" + } + }, + "@bitbybit-dev/occt": { + "version": "0.20.4", + "resolved": "https://registry.npmjs.org/@bitbybit-dev/occt/-/occt-0.20.4.tgz", + "integrity": "sha512-Lxx4wsToS3EIiS2L3KjUh6Jpgvxsyxbh2Jt4raWhIbD9PSy1zRfMww9K7xFlawSMgq12WN1a0lV8ydKs1f5/zw==", + "requires": { + "@bitbybit-dev/base": "0.20.4" + } + }, + "@bitbybit-dev/occt-worker": { + "version": "0.20.4", + "resolved": "https://registry.npmjs.org/@bitbybit-dev/occt-worker/-/occt-worker-0.20.4.tgz", + "integrity": "sha512-R5fiGteBSitv89Pz3XVgs+Vv0c1uH477oihkw1EUWLDTa7ypiXOohpjlKYFd/qAy3QCe8GEF3jDT+TK3dsQ+FA==", + "requires": { + "@bitbybit-dev/occt": "0.20.4", + "rxjs": "7.5.5" + } + }, + "@bitbybit-dev/threejs": { + "version": "0.20.4", + "resolved": "https://registry.npmjs.org/@bitbybit-dev/threejs/-/threejs-0.20.4.tgz", + "integrity": "sha512-kGRZDQFCmN6qEWeR62bniTT+kMJTzheRA0l3AIUOFzgKX5ZMxeV0lUv6gZgLnKHOLniC+Aa1o7p2uLQjGjD2MA==", + "requires": { + "@bitbybit-dev/core": "0.20.4", + "three": "0.176.0" + } + }, + "@dimforge/rapier3d-compat": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@dimforge/rapier3d-compat/-/rapier3d-compat-0.12.0.tgz", + "integrity": "sha512-uekIGetywIgopfD97oDL5PfeezkFpNhwlzlaEYNOA0N6ghdsOvh/HYjSMek5Q2O1PYvRSDFcqFVJl4r4ZBwOow==", + "dev": true + }, + "@esbuild/aix-ppc64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.3.tgz", + "integrity": "sha512-W8bFfPA8DowP8l//sxjJLSLkD8iEjMc7cBVyP+u4cEv9sM7mdUCkgsj+t0n/BWPFtv7WWCN5Yzj0N6FJNUUqBQ==", + "dev": true, + "optional": true + }, + "@esbuild/android-arm": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.3.tgz", + "integrity": "sha512-PuwVXbnP87Tcff5I9ngV0lmiSu40xw1At6i3GsU77U7cjDDB4s0X2cyFuBiDa1SBk9DnvWwnGvVaGBqoFWPb7A==", + "dev": true, + "optional": true + }, + "@esbuild/android-arm64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.3.tgz", + "integrity": "sha512-XelR6MzjlZuBM4f5z2IQHK6LkK34Cvv6Rj2EntER3lwCBFdg6h2lKbtRjpTTsdEjD/WSe1q8UyPBXP1x3i/wYQ==", + "dev": true, + "optional": true + }, + "@esbuild/android-x64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.3.tgz", + "integrity": "sha512-ogtTpYHT/g1GWS/zKM0cc/tIebFjm1F9Aw1boQ2Y0eUQ+J89d0jFY//s9ei9jVIlkYi8AfOjiixcLJSGNSOAdQ==", + "dev": true, + "optional": true + }, + "@esbuild/darwin-arm64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.3.tgz", + "integrity": "sha512-eESK5yfPNTqpAmDfFWNsOhmIOaQA59tAcF/EfYvo5/QWQCzXn5iUSOnqt3ra3UdzBv073ykTtmeLJZGt3HhA+w==", + "dev": true, + "optional": true + }, + "@esbuild/darwin-x64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.3.tgz", + "integrity": "sha512-Kd8glo7sIZtwOLcPbW0yLpKmBNWMANZhrC1r6K++uDR2zyzb6AeOYtI6udbtabmQpFaxJ8uduXMAo1gs5ozz8A==", + "dev": true, + "optional": true + }, + "@esbuild/freebsd-arm64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.3.tgz", + "integrity": "sha512-EJiyS70BYybOBpJth3M0KLOus0n+RRMKTYzhYhFeMwp7e/RaajXvP+BWlmEXNk6uk+KAu46j/kaQzr6au+JcIw==", + "dev": true, + "optional": true + }, + "@esbuild/freebsd-x64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.3.tgz", + "integrity": "sha512-Q+wSjaLpGxYf7zC0kL0nDlhsfuFkoN+EXrx2KSB33RhinWzejOd6AvgmP5JbkgXKmjhmpfgKZq24pneodYqE8Q==", + "dev": true, + "optional": true + }, + "@esbuild/linux-arm": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.3.tgz", + "integrity": "sha512-dUOVmAUzuHy2ZOKIHIKHCm58HKzFqd+puLaS424h6I85GlSDRZIA5ycBixb3mFgM0Jdh+ZOSB6KptX30DD8YOQ==", + "dev": true, + "optional": true + }, + "@esbuild/linux-arm64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.3.tgz", + "integrity": "sha512-xCUgnNYhRD5bb1C1nqrDV1PfkwgbswTTBRbAd8aH5PhYzikdf/ddtsYyMXFfGSsb/6t6QaPSzxtbfAZr9uox4A==", + "dev": true, + "optional": true + }, + "@esbuild/linux-ia32": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.3.tgz", + "integrity": "sha512-yplPOpczHOO4jTYKmuYuANI3WhvIPSVANGcNUeMlxH4twz/TeXuzEP41tGKNGWJjuMhotpGabeFYGAOU2ummBw==", + "dev": true, + "optional": true + }, + "@esbuild/linux-loong64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.3.tgz", + "integrity": "sha512-P4BLP5/fjyihmXCELRGrLd793q/lBtKMQl8ARGpDxgzgIKJDRJ/u4r1A/HgpBpKpKZelGct2PGI4T+axcedf6g==", + "dev": true, + "optional": true + }, + "@esbuild/linux-mips64el": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.3.tgz", + "integrity": "sha512-eRAOV2ODpu6P5divMEMa26RRqb2yUoYsuQQOuFUexUoQndm4MdpXXDBbUoKIc0iPa4aCO7gIhtnYomkn2x+bag==", + "dev": true, + "optional": true + }, + "@esbuild/linux-ppc64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.3.tgz", + "integrity": "sha512-ZC4jV2p7VbzTlnl8nZKLcBkfzIf4Yad1SJM4ZMKYnJqZFD4rTI+pBG65u8ev4jk3/MPwY9DvGn50wi3uhdaghg==", + "dev": true, + "optional": true + }, + "@esbuild/linux-riscv64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.3.tgz", + "integrity": "sha512-LDDODcFzNtECTrUUbVCs6j9/bDVqy7DDRsuIXJg6so+mFksgwG7ZVnTruYi5V+z3eE5y+BJZw7VvUadkbfg7QA==", + "dev": true, + "optional": true + }, + "@esbuild/linux-s390x": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.3.tgz", + "integrity": "sha512-s+w/NOY2k0yC2p9SLen+ymflgcpRkvwwa02fqmAwhBRI3SC12uiS10edHHXlVWwfAagYSY5UpmT/zISXPMW3tQ==", + "dev": true, + "optional": true + }, + "@esbuild/linux-x64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.3.tgz", + "integrity": "sha512-nQHDz4pXjSDC6UfOE1Fw9Q8d6GCAd9KdvMZpfVGWSJztYCarRgSDfOVBY5xwhQXseiyxapkiSJi/5/ja8mRFFA==", + "dev": true, + "optional": true + }, + "@esbuild/netbsd-arm64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.3.tgz", + "integrity": "sha512-1QaLtOWq0mzK6tzzp0jRN3eccmN3hezey7mhLnzC6oNlJoUJz4nym5ZD7mDnS/LZQgkrhEbEiTn515lPeLpgWA==", + "dev": true, + "optional": true + }, + "@esbuild/netbsd-x64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.3.tgz", + "integrity": "sha512-i5Hm68HXHdgv8wkrt+10Bc50zM0/eonPb/a/OFVfB6Qvpiirco5gBA5bz7S2SHuU+Y4LWn/zehzNX14Sp4r27g==", + "dev": true, + "optional": true + }, + "@esbuild/openbsd-arm64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.3.tgz", + "integrity": "sha512-zGAVApJEYTbOC6H/3QBr2mq3upG/LBEXr85/pTtKiv2IXcgKV0RT0QA/hSXZqSvLEpXeIxah7LczB4lkiYhTAQ==", + "dev": true, + "optional": true + }, + "@esbuild/openbsd-x64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.3.tgz", + "integrity": "sha512-fpqctI45NnCIDKBH5AXQBsD0NDPbEFczK98hk/aa6HJxbl+UtLkJV2+Bvy5hLSLk3LHmqt0NTkKNso1A9y1a4w==", + "dev": true, + "optional": true + }, + "@esbuild/sunos-x64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.3.tgz", + "integrity": "sha512-ROJhm7d8bk9dMCUZjkS8fgzsPAZEjtRJqCAmVgB0gMrvG7hfmPmz9k1rwO4jSiblFjYmNvbECL9uhaPzONMfgA==", + "dev": true, + "optional": true + }, + "@esbuild/win32-arm64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.3.tgz", + "integrity": "sha512-YWcow8peiHpNBiIXHwaswPnAXLsLVygFwCB3A7Bh5jRkIBFWHGmNQ48AlX4xDvQNoMZlPYzjVOQDYEzWCqufMQ==", + "dev": true, + "optional": true + }, + "@esbuild/win32-ia32": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.3.tgz", + "integrity": "sha512-qspTZOIGoXVS4DpNqUYUs9UxVb04khS1Degaw/MnfMe7goQ3lTfQ13Vw4qY/Nj0979BGvMRpAYbs/BAxEvU8ew==", + "dev": true, + "optional": true + }, + "@esbuild/win32-x64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.3.tgz", + "integrity": "sha512-ICgUR+kPimx0vvRzf+N/7L7tVSQeE3BYY+NhHRHXS1kBuPO7z2+7ea2HbhDyZdTephgvNvKrlDDKUexuCVBVvg==", + "dev": true, + "optional": true + }, + "@jscad/3mf-serializer": { + "version": "2.1.12", + "resolved": "https://registry.npmjs.org/@jscad/3mf-serializer/-/3mf-serializer-2.1.12.tgz", + "integrity": "sha512-+rxAIKIHCpaplupwwsdXtG1IdimPXFFB45nrjy6gdFHi36bEQW6y/RQD/ngenRiKnYSxu7/M0LatHcjve8z64A==", + "requires": { + "@jscad/array-utils": "2.1.4", + "@jscad/modeling": "2.12.3", + "fflate": "0.7.3", + "onml": "1.2.0" + } + }, + "@jscad/array-utils": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@jscad/array-utils/-/array-utils-2.1.4.tgz", + "integrity": "sha512-c31r4zSKsE+4Xfwk2V8monDA0hx5G89QGzaakWVUvuGNowYS9WSsYCwHiTIXodjR+HEnDu4okQ7k/whmP0Ne2g==" + }, + "@jscad/dxf-serializer": { + "version": "2.1.18", + "resolved": "https://registry.npmjs.org/@jscad/dxf-serializer/-/dxf-serializer-2.1.18.tgz", + "integrity": "sha512-T5Qe2jbEphcWAk7GaOY8PCMD4DPhTm6gWk/MPJCExphhnUwJqcU/1RiMb5hiD+N6hHzmlxD59I8QTjlp9LbLSA==", + "requires": { + "@jscad/array-utils": "2.1.4", + "@jscad/modeling": "2.12.3" + } + }, + "@jscad/io-utils": { + "version": "2.0.28", + "resolved": "https://registry.npmjs.org/@jscad/io-utils/-/io-utils-2.0.28.tgz", + "integrity": "sha512-spXh37wAgmwjKztoH/HANLgImcqRHX5+H/cRIxPfpqDIWvu7I5bRg2ZTwh25SYlKIzxPk4qX5Nu7Ax5+Kg+QXQ==" + }, + "@jscad/modeling": { + "version": "2.12.3", + "resolved": "https://registry.npmjs.org/@jscad/modeling/-/modeling-2.12.3.tgz", + "integrity": "sha512-DnAacXq3zhlYWIixGlFD7RMpgZAMuCaMZNQov0NaoFfs2GaBuTC5eqkqKcEVbhEerBmTllbjjF5IXjJMt9jcOA==" + }, + "@jscad/stl-serializer": { + "version": "2.1.18", + "resolved": "https://registry.npmjs.org/@jscad/stl-serializer/-/stl-serializer-2.1.18.tgz", + "integrity": "sha512-pz++TRjHI7jBPnnxQUi4B/uYUG3yCDsKlw8+xL2kumwjb+auc6Ng6Rnr/GqUTkgHrnGut08wg/8AekyWjvBwYg==", + "requires": { + "@jscad/array-utils": "2.1.4", + "@jscad/modeling": "2.12.3" + } + }, + "@jsep-plugin/assignment": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@jsep-plugin/assignment/-/assignment-1.3.0.tgz", + "integrity": "sha512-VVgV+CXrhbMI3aSusQyclHkenWSAm95WaiKrMxRFam3JSUiIaQjoMIw2sEs/OX4XifnqeQUN4DYbJjlA8EfktQ==", + "requires": {} + }, + "@jsep-plugin/regex": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@jsep-plugin/regex/-/regex-1.0.4.tgz", + "integrity": "sha512-q7qL4Mgjs1vByCaTnDFcBnV9HS7GVPJX5vyVoCgZHNSC9rjwIlmbXG5sUuorR5ndfHAIlJ8pVStxvjXHbNvtUg==", + "requires": {} + }, + "@rollup/rollup-android-arm-eabi": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.40.1.tgz", + "integrity": "sha512-kxz0YeeCrRUHz3zyqvd7n+TVRlNyTifBsmnmNPtk3hQURUyG9eAB+usz6DAwagMusjx/zb3AjvDUvhFGDAexGw==", + "dev": true, + "optional": true + }, + "@rollup/rollup-android-arm64": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.40.1.tgz", + "integrity": "sha512-PPkxTOisoNC6TpnDKatjKkjRMsdaWIhyuMkA4UsBXT9WEZY4uHezBTjs6Vl4PbqQQeu6oION1w2voYZv9yquCw==", + "dev": true, + "optional": true + }, + "@rollup/rollup-darwin-arm64": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.40.1.tgz", + "integrity": "sha512-VWXGISWFY18v/0JyNUy4A46KCFCb9NVsH+1100XP31lud+TzlezBbz24CYzbnA4x6w4hx+NYCXDfnvDVO6lcAA==", + "dev": true, + "optional": true + }, + "@rollup/rollup-darwin-x64": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.40.1.tgz", + "integrity": "sha512-nIwkXafAI1/QCS7pxSpv/ZtFW6TXcNUEHAIA9EIyw5OzxJZQ1YDrX+CL6JAIQgZ33CInl1R6mHet9Y/UZTg2Bw==", + "dev": true, + "optional": true + }, + "@rollup/rollup-freebsd-arm64": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.40.1.tgz", + "integrity": "sha512-BdrLJ2mHTrIYdaS2I99mriyJfGGenSaP+UwGi1kB9BLOCu9SR8ZpbkmmalKIALnRw24kM7qCN0IOm6L0S44iWw==", + "dev": true, + "optional": true + }, + "@rollup/rollup-freebsd-x64": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.40.1.tgz", + "integrity": "sha512-VXeo/puqvCG8JBPNZXZf5Dqq7BzElNJzHRRw3vjBE27WujdzuOPecDPc/+1DcdcTptNBep3861jNq0mYkT8Z6Q==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.40.1.tgz", + "integrity": "sha512-ehSKrewwsESPt1TgSE/na9nIhWCosfGSFqv7vwEtjyAqZcvbGIg4JAcV7ZEh2tfj/IlfBeZjgOXm35iOOjadcg==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-arm-musleabihf": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.40.1.tgz", + "integrity": "sha512-m39iO/aaurh5FVIu/F4/Zsl8xppd76S4qoID8E+dSRQvTyZTOI2gVk3T4oqzfq1PtcvOfAVlwLMK3KRQMaR8lg==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-arm64-gnu": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.40.1.tgz", + "integrity": "sha512-Y+GHnGaku4aVLSgrT0uWe2o2Rq8te9hi+MwqGF9r9ORgXhmHK5Q71N757u0F8yU1OIwUIFy6YiJtKjtyktk5hg==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-arm64-musl": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.40.1.tgz", + "integrity": "sha512-jEwjn3jCA+tQGswK3aEWcD09/7M5wGwc6+flhva7dsQNRZZTe30vkalgIzV4tjkopsTS9Jd7Y1Bsj6a4lzz8gQ==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.40.1.tgz", + "integrity": "sha512-ySyWikVhNzv+BV/IDCsrraOAZ3UaC8SZB67FZlqVwXwnFhPihOso9rPOxzZbjp81suB1O2Topw+6Ug3JNegejQ==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.40.1.tgz", + "integrity": "sha512-BvvA64QxZlh7WZWqDPPdt0GH4bznuL6uOO1pmgPnnv86rpUpc8ZxgZwcEgXvo02GRIZX1hQ0j0pAnhwkhwPqWg==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-riscv64-gnu": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.40.1.tgz", + "integrity": "sha512-EQSP+8+1VuSulm9RKSMKitTav89fKbHymTf25n5+Yr6gAPZxYWpj3DzAsQqoaHAk9YX2lwEyAf9S4W8F4l3VBQ==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-riscv64-musl": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.40.1.tgz", + "integrity": "sha512-n/vQ4xRZXKuIpqukkMXZt9RWdl+2zgGNx7Uda8NtmLJ06NL8jiHxUawbwC+hdSq1rrw/9CghCpEONor+l1e2gA==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-s390x-gnu": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.40.1.tgz", + "integrity": "sha512-h8d28xzYb98fMQKUz0w2fMc1XuGzLLjdyxVIbhbil4ELfk5/orZlSTpF/xdI9C8K0I8lCkq+1En2RJsawZekkg==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-x64-gnu": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.40.1.tgz", + "integrity": "sha512-XiK5z70PEFEFqcNj3/zRSz/qX4bp4QIraTy9QjwJAb/Z8GM7kVUsD0Uk8maIPeTyPCP03ChdI+VVmJriKYbRHQ==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-x64-musl": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.40.1.tgz", + "integrity": "sha512-2BRORitq5rQ4Da9blVovzNCMaUlyKrzMSvkVR0D4qPuOy/+pMCrh1d7o01RATwVy+6Fa1WBw+da7QPeLWU/1mQ==", + "dev": true, + "optional": true + }, + "@rollup/rollup-win32-arm64-msvc": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.40.1.tgz", + "integrity": "sha512-b2bcNm9Kbde03H+q+Jjw9tSfhYkzrDUf2d5MAd1bOJuVplXvFhWz7tRtWvD8/ORZi7qSCy0idW6tf2HgxSXQSg==", + "dev": true, + "optional": true + }, + "@rollup/rollup-win32-ia32-msvc": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.40.1.tgz", + "integrity": "sha512-DfcogW8N7Zg7llVEfpqWMZcaErKfsj9VvmfSyRjCyo4BI3wPEfrzTtJkZG6gKP/Z92wFm6rz2aDO7/JfiR/whA==", + "dev": true, + "optional": true + }, + "@rollup/rollup-win32-x64-msvc": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.40.1.tgz", + "integrity": "sha512-ECyOuDeH3C1I8jH2MK1RtBJW+YPMvSfT0a5NN0nHfQYnDSJ6tUiZH3gzwVP5/Kfh/+Tt7tpWVF9LXNTnhTJ3kA==", + "dev": true, + "optional": true + }, + "@tweenjs/tween.js": { + "version": "23.1.3", + "resolved": "https://registry.npmjs.org/@tweenjs/tween.js/-/tween.js-23.1.3.tgz", + "integrity": "sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA==", + "dev": true + }, + "@types/estree": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", + "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==", + "dev": true + }, + "@types/stats.js": { + "version": "0.17.3", + "resolved": "https://registry.npmjs.org/@types/stats.js/-/stats.js-0.17.3.tgz", + "integrity": "sha512-pXNfAD3KHOdif9EQXZ9deK82HVNaXP5ZIF5RP2QG6OQFNTaY2YIetfrE9t528vEreGQvEPRDDc8muaoYeK0SxQ==", + "dev": true + }, + "@types/three": { + "version": "0.176.0", + "resolved": "https://registry.npmjs.org/@types/three/-/three-0.176.0.tgz", + "integrity": "sha512-FwfPXxCqOtP7EdYMagCFePNKoG1AGBDUEVKtluv2BTVRpSt7b+X27xNsirPCTCqY1pGYsPUzaM3jgWP7dXSxlw==", + "dev": true, + "requires": { + "@dimforge/rapier3d-compat": "^0.12.0", + "@tweenjs/tween.js": "~23.1.3", + "@types/stats.js": "*", + "@types/webxr": "*", + "@webgpu/types": "*", + "fflate": "~0.8.2", + "meshoptimizer": "~0.18.1" + }, + "dependencies": { + "fflate": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz", + "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==", + "dev": true + } + } + }, + "@types/webxr": { + "version": "0.5.22", + "resolved": "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.22.tgz", + "integrity": "sha512-Vr6Stjv5jPRqH690f5I5GLjVk8GSsoQSYJ2FVd/3jJF7KaqfwPi3ehfBS96mlQ2kPCwZaX6U0rG2+NGHBKkA/A==", + "dev": true + }, + "@webgpu/types": { + "version": "0.1.60", + "resolved": "https://registry.npmjs.org/@webgpu/types/-/types-0.1.60.tgz", + "integrity": "sha512-8B/tdfRFKdrnejqmvq95ogp8tf52oZ51p3f4QD5m5Paey/qlX4Rhhy5Y8tgFMi7Ms70HzcMMw3EQjH/jdhTwlA==", + "dev": true + }, + "bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "optional": true, + "requires": { + "file-uri-to-path": "1.0.0" + } + }, + "esbuild": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.3.tgz", + "integrity": "sha512-qKA6Pvai73+M2FtftpNKRxJ78GIjmFXFxd/1DVBqGo/qNhLSfv+G12n9pNoWdytJC8U00TrViOwpjT0zgqQS8Q==", + "dev": true, + "requires": { + "@esbuild/aix-ppc64": "0.25.3", + "@esbuild/android-arm": "0.25.3", + "@esbuild/android-arm64": "0.25.3", + "@esbuild/android-x64": "0.25.3", + "@esbuild/darwin-arm64": "0.25.3", + "@esbuild/darwin-x64": "0.25.3", + "@esbuild/freebsd-arm64": "0.25.3", + "@esbuild/freebsd-x64": "0.25.3", + "@esbuild/linux-arm": "0.25.3", + "@esbuild/linux-arm64": "0.25.3", + "@esbuild/linux-ia32": "0.25.3", + "@esbuild/linux-loong64": "0.25.3", + "@esbuild/linux-mips64el": "0.25.3", + "@esbuild/linux-ppc64": "0.25.3", + "@esbuild/linux-riscv64": "0.25.3", + "@esbuild/linux-s390x": "0.25.3", + "@esbuild/linux-x64": "0.25.3", + "@esbuild/netbsd-arm64": "0.25.3", + "@esbuild/netbsd-x64": "0.25.3", + "@esbuild/openbsd-arm64": "0.25.3", + "@esbuild/openbsd-x64": "0.25.3", + "@esbuild/sunos-x64": "0.25.3", + "@esbuild/win32-arm64": "0.25.3", + "@esbuild/win32-ia32": "0.25.3", + "@esbuild/win32-x64": "0.25.3" + } + }, + "fdir": { + "version": "6.4.4", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.4.tgz", + "integrity": "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==", + "dev": true, + "requires": {} + }, + "fflate": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.7.3.tgz", + "integrity": "sha512-0Zz1jOzJWERhyhsimS54VTqOteCNwRtIlh8isdL0AXLo0g7xNTfTL7oWrkmCnPhZGocKIkWHBistBrrpoNH3aw==" + }, + "file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "optional": true + }, + "fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "optional": true + }, + "jsep": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/jsep/-/jsep-1.4.0.tgz", + "integrity": "sha512-B7qPcEVE3NVkmSJbaYxvv4cHkVW7DQsZz13pUMrfS8z8Q/BuShN+gcTXrUlPiGqM2/t/EEaI030bpxMqY8gMlw==" + }, + "jsonpath-plus": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/jsonpath-plus/-/jsonpath-plus-10.1.0.tgz", + "integrity": "sha512-gHfV1IYqH8uJHYVTs8BJX1XKy2/rR93+f8QQi0xhx95aCiXn1ettYAd5T+7FU6wfqyDoX/wy0pm/fL3jOKJ9Lg==", + "requires": { + "@jsep-plugin/assignment": "^1.2.1", + "@jsep-plugin/regex": "^1.0.3", + "jsep": "^1.3.9" + } + }, + "lil-gui": { + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/lil-gui/-/lil-gui-0.20.0.tgz", + "integrity": "sha512-k7Ipr0ztqslMA2XvM5z5ZaWhxQtnEOwJBfI/hmSuRh6q4iMG9L0boqqrnZSzBR1jzyJ28OMl47l65ILzRe1TdA==" + }, + "manifold-3d": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/manifold-3d/-/manifold-3d-3.0.0.tgz", + "integrity": "sha512-6XxRf5LH4s7WIlRrvtzLMg+CHio5TznIE0w0PU/Ad8IzD36QLjb64QdSeQp9ISrk4tGtIqVAycevpPe1ExGTKg==" + }, + "meshoptimizer": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/meshoptimizer/-/meshoptimizer-0.18.1.tgz", + "integrity": "sha512-ZhoIoL7TNV4s5B6+rx5mC//fw8/POGyNxS/DZyCJeiZ12ScLfVwRE/GfsxwiTkMYYD5DmK2/JXnEVXqL4rF+Sw==", + "dev": true + }, + "nan": { + "version": "2.22.2", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.22.2.tgz", + "integrity": "sha512-DANghxFkS1plDdRsX0X9pm0Z6SJNN6gBdtXfanwoZ8hooC5gosGFSBGRYHUVPz1asKA/kMRqDRdHrluZ61SpBQ==", + "optional": true + }, + "nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true + }, + "onml": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/onml/-/onml-1.2.0.tgz", + "integrity": "sha512-olqYAg18XoHAhm7tK9DdBCOVdts70DGmMgCNLOWyqZokht2utgGSKBB4JHi6pBZpmioAhcYlxK+91L3tsrz+GA==", + "requires": { + "sax": "^1.2.1" + } + }, + "picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true + }, + "picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true + }, + "postcss": { + "version": "8.5.3", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz", + "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==", + "dev": true, + "requires": { + "nanoid": "^3.3.8", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + } + }, + "rollup": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.40.1.tgz", + "integrity": "sha512-C5VvvgCCyfyotVITIAv+4efVytl5F7wt+/I2i9q9GZcEXW9BP52YYOXC58igUi+LFZVHukErIIqQSWwv/M3WRw==", + "dev": true, + "requires": { + "@rollup/rollup-android-arm-eabi": "4.40.1", + "@rollup/rollup-android-arm64": "4.40.1", + "@rollup/rollup-darwin-arm64": "4.40.1", + "@rollup/rollup-darwin-x64": "4.40.1", + "@rollup/rollup-freebsd-arm64": "4.40.1", + "@rollup/rollup-freebsd-x64": "4.40.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.40.1", + "@rollup/rollup-linux-arm-musleabihf": "4.40.1", + "@rollup/rollup-linux-arm64-gnu": "4.40.1", + "@rollup/rollup-linux-arm64-musl": "4.40.1", + "@rollup/rollup-linux-loongarch64-gnu": "4.40.1", + "@rollup/rollup-linux-powerpc64le-gnu": "4.40.1", + "@rollup/rollup-linux-riscv64-gnu": "4.40.1", + "@rollup/rollup-linux-riscv64-musl": "4.40.1", + "@rollup/rollup-linux-s390x-gnu": "4.40.1", + "@rollup/rollup-linux-x64-gnu": "4.40.1", + "@rollup/rollup-linux-x64-musl": "4.40.1", + "@rollup/rollup-win32-arm64-msvc": "4.40.1", + "@rollup/rollup-win32-ia32-msvc": "4.40.1", + "@rollup/rollup-win32-x64-msvc": "4.40.1", + "@types/estree": "1.0.7", + "fsevents": "~2.3.2" + } + }, + "rxjs": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.5.tgz", + "integrity": "sha512-sy+H0pQofO95VDmFLzyaw9xNJU4KTRSwQIGM6+iG3SypAtCiLDzpeG8sJrNCWn2Up9km+KhkvTdbkrdy+yzZdw==", + "requires": { + "tslib": "^2.1.0" + } + }, + "sax": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", + "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==" + }, + "source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true + }, + "three": { + "version": "0.176.0", + "resolved": "https://registry.npmjs.org/three/-/three-0.176.0.tgz", + "integrity": "sha512-PWRKYWQo23ojf9oZSlRGH8K09q7nRSWx6LY/HF/UUrMdYgN9i1e2OwJYHoQjwc6HF/4lvvYLC5YC1X8UJL2ZpA==" + }, + "tinyglobby": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.13.tgz", + "integrity": "sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==", + "dev": true, + "requires": { + "fdir": "^6.4.4", + "picomatch": "^4.0.2" + } + }, + "tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" + }, + "typescript": { + "version": "5.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", + "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", + "dev": true + }, + "verb-nurbs-web": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/verb-nurbs-web/-/verb-nurbs-web-2.1.3.tgz", + "integrity": "sha512-2PvI2bx7dn0r3kWtk+JuDIDZ+p7I5Piu8y6/ZNhUVpilOyHKK1nNzLHtgown+dFOmBnKnuAKIMh1xn/5kzrxZA==", + "requires": { + "webworker-threads": "^0.7.12" + } + }, + "vite": { + "version": "6.3.4", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.4.tgz", + "integrity": "sha512-BiReIiMS2fyFqbqNT/Qqt4CVITDU9M9vE+DKcVAsB+ZV0wvTKd+3hMbkpxz1b+NmEDMegpVbisKiAZOnvO92Sw==", + "dev": true, + "requires": { + "esbuild": "^0.25.0", + "fdir": "^6.4.4", + "fsevents": "~2.3.3", + "picomatch": "^4.0.2", + "postcss": "^8.5.3", + "rollup": "^4.34.9", + "tinyglobby": "^0.2.13" + } + }, + "webworker-threads": { + "version": "0.7.17", + "resolved": "https://registry.npmjs.org/webworker-threads/-/webworker-threads-0.7.17.tgz", + "integrity": "sha512-Y2w2aXBbDLk9IzTEb9u+MsODC3s4YlGI7g4h0t+1OAwIO8yBI9rQL35ZYlyayiCuWu1dZMH/P7kGU8OwW7YsyA==", + "optional": true, + "requires": { + "bindings": "^1.3.0", + "nan": "^2.11.0" + } + } } } diff --git a/examples/vite/threejs/hex-shell/src/create-shape.ts b/examples/vite/threejs/hex-shell/src/create-shape.ts deleted file mode 100644 index 48ee7afb..00000000 --- a/examples/vite/threejs/hex-shell/src/create-shape.ts +++ /dev/null @@ -1,658 +0,0 @@ -import type { BitByBitBase } from '@bitbybit-dev/threejs'; -import { Color, DoubleSide, Group, MeshPhongMaterial, Scene } from 'three'; -import { Inputs } from '@bitbybit-dev/threejs'; -import type { Current } from './models/current'; -import type { Model } from './models/model'; - -export const createShapeLod2 = async ( - bitbybit: BitByBitBase | undefined, - scene: Scene | undefined, - model: Model, - shapesToClean: Inputs.OCCT.TopoDSShapePointer[], - current: Current -) => { - if (scene && bitbybit) { - if (shapesToClean.length > 0) { - await bitbybit.occt.deleteShapes({ shapes: shapesToClean }); - } - if (shapesToClean.length > 0) { - await bitbybit.occt.deleteShapes({ shapes: shapesToClean }); - } - - const { loft } = await createFaceAndEllipses(bitbybit, model); - shapesToClean.push(loft); - const faces = await bitbybit.occt.shapes.face.getFaces({ - shape: loft, - }); - - const faceBase = faces[0]; - shapesToClean.push(faceBase); - - const getFace = (l: Inputs.OCCT.TopoDSShapePointer) => { - return bitbybit.occt.shapes.face.getFace({ shape: l, index: 0 }); - }; - - const loft1 = await bitbybit.occt.operations.offset({ - shape: faceBase, - distance: -1.5, - tolerance: 1e-6, - }); - shapesToClean.push(loft1); - - const face1 = await getFace(loft1); - shapesToClean.push(face1); - - const loft3 = await bitbybit.occt.operations.offset({ - shape: faceBase, - distance: 1.5, - tolerance: 1e-6, - }); - shapesToClean.push(loft3); - - const loft4 = await bitbybit.occt.operations.offset({ - shape: faceBase, - distance: 3, - tolerance: 1e-6, - }); - shapesToClean.push(loft4); - - const loft5 = await bitbybit.occt.operations.offset({ - shape: faceBase, - distance: 5, - tolerance: 1e-6, - }); - shapesToClean.push(loft5); - - const face2 = faceBase; - const face3 = await getFace(loft3); - const face4 = await getFace(loft4); - const face5 = await getFace(loft5); - shapesToClean.push(face3); - shapesToClean.push(face4); - shapesToClean.push(face5); - - const subdivideOptions = new Inputs.OCCT.FaceSubdivideToHexagonWiresDto( - face1 - ); - subdivideOptions.nrHexagonsU = model.vHex; - subdivideOptions.nrHexagonsV = model.uHex; - subdivideOptions.extendUUp = true; - subdivideOptions.filletPattern = [0.8]; - subdivideOptions.scalePatternU = [0.4, 0.3, 0.2]; - subdivideOptions.scalePatternV = [0.4, 0.3, 0.2]; - const thickness = 0.1; - const wrs1Out = await bitbybit.occt.shapes.face.subdivideToHexagonWires( - subdivideOptions - ); - subdivideOptions.scalePatternU = [ - 0.4 - thickness, - 0.3 - thickness, - 0.2 - thickness, - ]; - subdivideOptions.scalePatternV = [ - 0.4 - thickness, - 0.3 - thickness, - 0.2 - thickness, - ]; - shapesToClean.push(...wrs1Out); - - const wrs1In = await bitbybit.occt.shapes.face.subdivideToHexagonWires( - subdivideOptions - ); - shapesToClean.push(...wrs1In); - - subdivideOptions.scalePatternU = [1]; - subdivideOptions.scalePatternV = [1]; - subdivideOptions.filletPattern = [0.001]; - subdivideOptions.shape = face2; - const wrs2Out = await bitbybit.occt.shapes.face.subdivideToHexagonWires( - subdivideOptions - ); - shapesToClean.push(...wrs2Out); - - subdivideOptions.filletPattern = [0.8]; - subdivideOptions.scalePatternU = [0.4]; - subdivideOptions.scalePatternV = [0.4]; - const wrs2In = await bitbybit.occt.shapes.face.subdivideToHexagonWires( - subdivideOptions - ); - shapesToClean.push(...wrs2In); - - subdivideOptions.scalePatternU = [0.98]; - subdivideOptions.scalePatternV = [0.98]; - subdivideOptions.shape = face3; - subdivideOptions.filletPattern = [0.001]; - const wrs3Out = await bitbybit.occt.shapes.face.subdivideToHexagonWires( - subdivideOptions - ); - shapesToClean.push(...wrs3Out); - - subdivideOptions.scalePatternU = [0.4]; - subdivideOptions.scalePatternV = [0.4]; - subdivideOptions.filletPattern = [0.9]; - const wrs3In = await bitbybit.occt.shapes.face.subdivideToHexagonWires( - subdivideOptions - ); - shapesToClean.push(...wrs3In); - - subdivideOptions.scalePatternU = [1]; - subdivideOptions.scalePatternV = [1]; - subdivideOptions.filletPattern = [0.001]; - subdivideOptions.shape = face4; - const wrs4Out = await bitbybit.occt.shapes.face.subdivideToHexagonWires( - subdivideOptions - ); - shapesToClean.push(...wrs4Out); - - subdivideOptions.scalePatternU = [0.3]; - subdivideOptions.scalePatternV = [0.3]; - subdivideOptions.filletPattern = [0.8]; - const wrs4In = await bitbybit.occt.shapes.face.subdivideToHexagonWires( - subdivideOptions - ); - shapesToClean.push(...wrs4In); - - subdivideOptions.scalePatternU = [0.9]; - subdivideOptions.scalePatternV = [0.9]; - subdivideOptions.filletPattern = [0.3]; - const wrs4InSpec = await bitbybit.occt.shapes.face.subdivideToHexagonWires( - subdivideOptions - ); - shapesToClean.push(...wrs4InSpec); - - subdivideOptions.scalePatternU = [0.4, 0.3, 0.2]; - subdivideOptions.scalePatternV = [0.4, 0.3, 0.2]; - subdivideOptions.shape = face5; - subdivideOptions.filletPattern = [0.9]; - const wrs5Out = await bitbybit.occt.shapes.face.subdivideToHexagonWires( - subdivideOptions - ); - shapesToClean.push(...wrs5Out); - - subdivideOptions.scalePatternU = [ - 0.4 - thickness, - 0.3 - thickness, - 0.2 - thickness, - ]; - subdivideOptions.scalePatternV = [ - 0.4 - thickness, - 0.3 - thickness, - 0.2 - thickness, - ]; - subdivideOptions.filletPattern = [0.9]; - - const wrs5In = await bitbybit.occt.shapes.face.subdivideToHexagonWires( - subdivideOptions - ); - shapesToClean.push(...wrs5In); - - const loftPromises: Promise[] = []; - const loftOptions = - new Inputs.OCCT.LoftAdvancedDto(); - loftOptions.straight = true; - loftOptions.closed = true; - - const indexes1: number[] = []; - const indexes2: number[] = []; - wrs1Out.forEach((w1Out, index) => { - const w1In = wrs1In[index]; - const w2Out = wrs2Out[index]; - const w2In = wrs2In[index]; - const w3Out = wrs3Out[index]; - const w3In = wrs3In[index]; - const w4Out = wrs4Out[index]; - const w4In = wrs4In[index]; - const w4InSpec = wrs4InSpec[index]; - const w5Out = wrs5Out[index]; - const w5In = wrs5In[index]; - - if (index % 3 === 0) { - indexes1.push(index); - loftOptions.shapes = [ - w1In, - w2In, - w3In, - w4In, - w5In, - w5Out, - w4Out, - w3Out, - w2Out, - w1Out, - ].reverse(); - } else { - indexes2.push(index); - loftOptions.shapes = [ - w2In, - w3In, - w4InSpec, - w4Out, - w3Out, - w2Out, - ].reverse(); - } - - const lft = bitbybit.occt.operations.loftAdvanced(loftOptions); - loftPromises.push(lft); - }); - - const lofts: Inputs.OCCT.TopoDSShapePointer[] = await Promise.all( - loftPromises - ); - shapesToClean.push(...lofts); - const lofts1: Inputs.OCCT.TopoDSShapePointer[] = indexes1.map( - (i) => lofts[i] - ); - const lofts2: Inputs.OCCT.TopoDSShapePointer[] = indexes2.map( - (i) => lofts[i] - ); - - const chunkSize = 40; - const lofts1Chunked = bitbybit.lists.groupNth({ - list: lofts1, - nrElements: chunkSize, - keepRemainder: true, - }); - const lofts2Chunked = bitbybit.lists.groupNth({ - list: lofts2, - nrElements: chunkSize, - keepRemainder: true, - }); - - const compounds1ToDrawPromises = lofts1Chunked.map((lchunk) => - bitbybit.occt.shapes.compound.makeCompound({ - shapes: lchunk, - }) - ); - - const compounds2ToDrawPromises = lofts2Chunked.map((lchunk) => - bitbybit.occt.shapes.compound.makeCompound({ - shapes: lchunk, - }) - ); - - const compounds1ToDraw = await Promise.all(compounds1ToDrawPromises); - const compounds2ToDraw = await Promise.all(compounds2ToDrawPromises); - - shapesToClean.push(...compounds1ToDraw); - shapesToClean.push(...compounds2ToDraw); - - const finalShape = await bitbybit.occt.shapes.compound.makeCompound({ - shapes: [...lofts1, ...lofts2], - }); - - shapesToClean.push(finalShape); - - // DRAWING BEGINS - - const options = new Inputs.Draw.DrawOcctShapeOptions(); - options.precision = model.finalPrecision; - options.drawEdges = model.drawEdges; - options.drawFaces = model.drawFaces; - options.drawVertices = false; - options.edgeWidth = 20; - options.edgeColour = '#000000'; - - const mat = new MeshPhongMaterial({ color: new Color(model.color1) }); - if (model.drawEdges) { - mat.polygonOffset = true; - mat.polygonOffsetFactor = 1; - } - options.faceMaterial = mat; - - const groups1Promises = compounds1ToDraw.map((comp) => - bitbybit.draw.drawAnyAsync({ entity: comp, options }) - ); - - const mat2 = new MeshPhongMaterial({ color: new Color(model.color2) }); - if (model.drawEdges) { - mat2.polygonOffset = true; - mat2.polygonOffsetFactor = 1; - } - options.faceMaterial = mat2; - - const groups2Promises = compounds2ToDraw.map((comp) => - bitbybit.draw.drawAnyAsync({ entity: comp, options }) - ); - - const groups1 = await Promise.all(groups1Promises); - const groups2 = await Promise.all(groups2Promises); - - const group1 = new Group(); - group1.add(...groups1); - scene.add(group1); - - const group2 = new Group(); - group2.add(...groups2); - scene.add(group2); - - groups1.forEach((group) => { - group.children[0].children.forEach((child) => { - child.castShadow = true; - child.receiveShadow = true; - }); - }); - - groups2.forEach((group) => { - group.children[0].children.forEach((child) => { - child.castShadow = true; - child.receiveShadow = true; - }); - }); - - current.group1 = group1; - current.group2 = group2; - return finalShape; - } -}; - -export const createShapeLod1 = async ( - bitbybit: BitByBitBase | undefined, - scene: Scene | undefined, - model: Model, - shapesToClean: Inputs.OCCT.TopoDSShapePointer[], - current: Current -) => { - if (scene && bitbybit) { - if (shapesToClean.length > 0) { - await bitbybit.occt.deleteShapes({ shapes: shapesToClean }); - } - if (shapesToClean.length > 0) { - await bitbybit.occt.deleteShapes({ shapes: shapesToClean }); - } - - const { loft, w1, w2, w3 } = await createFaceAndEllipses(bitbybit, model); - shapesToClean.push(loft, w1, w2, w3); - const faces = await bitbybit.occt.shapes.face.getFaces({ - shape: loft, - }); - - const faceBase = faces[0]; - shapesToClean.push(faceBase); - - const subdivideOptions = new Inputs.OCCT.FaceSubdivideToHexagonWiresDto( - faceBase - ); - subdivideOptions.nrHexagonsU = model.vHex; - subdivideOptions.nrHexagonsV = model.uHex; - subdivideOptions.extendUUp = true; - const wrs1Out = await bitbybit.occt.shapes.face.subdivideToHexagonWires( - subdivideOptions - ); - shapesToClean.push(...wrs1Out); - - const fcs: Inputs.OCCT.TopoDSFacePointer[] = - (await bitbybit.occt.shapes.face.createFacesFromWiresOnFace({ - wires: wrs1Out, - face: faceBase, - inside: true, - })) as any; - - shapesToClean.push(...fcs); - const firstGroupFcs: Inputs.OCCT.TopoDSFacePointer[] = []; - const secondGroupFcs: Inputs.OCCT.TopoDSFacePointer[] = []; - fcs.forEach((f, index) => { - if (index % 3 === 0) { - firstGroupFcs.push(f); - } else { - secondGroupFcs.push(f); - } - }); - - const firstGroup = await bitbybit.occt.shapes.compound.makeCompound({ - shapes: firstGroupFcs, - }); - shapesToClean.push(firstGroup); - const secondGroup = await bitbybit.occt.shapes.compound.makeCompound({ - shapes: secondGroupFcs, - }); - shapesToClean.push(secondGroup); - - const dimensions = await createDimensions( - bitbybit, - model, - faceBase, - [w1, w2, w3], - shapesToClean - ); - - shapesToClean.push(dimensions); - - const options = new Inputs.Draw.DrawOcctShapeOptions(); - options.precision = 0.01; - options.drawEdges = true; - options.drawFaces = true; - options.drawVertices = false; - options.edgeWidth = 20; - - options.edgeColour = '#ffffff'; - - const mat = new MeshPhongMaterial({ color: new Color(model.color1) }); - mat.polygonOffset = true; - mat.polygonOffsetFactor = 1; - mat.transparent = true; - mat.opacity = 0.5; - mat.side = DoubleSide; - options.faceMaterial = mat; - const grp1 = await bitbybit.draw.drawAnyAsync({ - entity: firstGroup, - options, - }); - - const mat2 = new MeshPhongMaterial({ color: new Color(model.color2) }); - mat2.polygonOffset = true; - mat2.polygonOffsetFactor = 1; - mat2.transparent = true; - mat2.opacity = 0.5; - mat2.side = DoubleSide; - options.faceMaterial = mat2; - const grp2 = await bitbybit.draw.drawAnyAsync({ - entity: secondGroup, - options, - }); - - grp1.children[0].children.forEach((child) => { - child.castShadow = true; - child.receiveShadow = true; - }); - - grp2.children[0].children.forEach((child) => { - child.castShadow = true; - child.receiveShadow = true; - }); - - const dimOpt = new Inputs.Draw.DrawOcctShapeOptions(); - dimOpt.edgeColour = '#aaaaff'; - dimOpt.drawFaces = false; - const dimensionsGroup = await bitbybit.draw.drawAnyAsync({ - entity: dimensions, - options: dimOpt, - }); - dimensionsGroup.position.y = 0.02; - - // just to match chunked data structure of LOD2 - const group1 = new Group(); - group1.add(grp1); - scene.add(group1); - const group2 = new Group(); - group2.add(grp2); - scene.add(group2); - - current.group1 = group1; - current.group2 = group2; - current.dimensions = dimensionsGroup; - - const finalShape = await bitbybit.occt.shapes.compound.makeCompound({ - shapes: [firstGroup, secondGroup, dimensions], - }); - - return finalShape; - } -}; - -async function createFaceAndEllipses(bitbybit: BitByBitBase, model: Model) { - const ellipseOptions = new Inputs.OCCT.EllipseDto(); - const { wire } = bitbybit.occt.shapes; - const { transforms, operations } = bitbybit.occt; - - ellipseOptions.radiusMinor = model.ellipse1MinRad; - ellipseOptions.radiusMajor = model.ellipse1MaxRad; - const w1 = await wire.createEllipseWire(ellipseOptions); - - ellipseOptions.radiusMinor = model.ellipse2MinRad; - ellipseOptions.radiusMajor = model.ellipse2MaxRad; - const w2s = await wire.createEllipseWire(ellipseOptions); - - let w2r1; - if (model.ellipse2RotX > 0) { - w2r1 = await transforms.rotate({ - shape: w2s, - angle: model.ellipse2RotX, - axis: [1, 0, 0], - }); - } else { - w2r1 = w2s; - } - - const w2r2 = await transforms.rotate({ - shape: w2r1, - angle: model.ellipse2RotY, - axis: [0, 1, 0], - }); - const w2 = await transforms.translate({ - shape: w2r2, - translation: [0, model.height, 0], - }); - - ellipseOptions.radiusMinor = model.ellipse3MinRad; - ellipseOptions.radiusMajor = model.ellipse3MaxRad; - const w3s = await wire.createEllipseWire(ellipseOptions); - const w3 = await transforms.rotate({ - shape: w3s, - angle: model.ellipse3YRot, - axis: [0, 1, 0], - }); - const loft = await operations.loft({ - shapes: [w3, w2, w1], - makeSolid: false, - }); - - return { loft, w1, w2, w3 }; -} - -async function createDimensions( - bitbybit: BitByBitBase, - model: Model, - faceBase: Inputs.OCCT.TopoDSFacePointer, - wires: Inputs.OCCT.TopoDSWirePointer[], - shapesToClean: Inputs.OCCT.TopoDSShapePointer[] -) { - const subOpt = - new Inputs.OCCT.FaceSubdivisionDto(); - subOpt.shape = faceBase; - subOpt.nrDivisionsU = 50; - subOpt.nrDivisionsV = 50; - const pts = await bitbybit.occt.shapes.face.subdivideToPoints(subOpt); - const bbox = bitbybit.point.boundingBoxOfPoints({ points: pts }); - - const { dimensions, shapes } = bitbybit.occt; - const linearOptions = new Inputs.OCCT.SimpleLinearLengthDimensionDto(); - - linearOptions.start = [-model.ellipse3MaxRad, 0.01, 0]; - linearOptions.end = [model.ellipse3MaxRad, 0.01, 0]; - linearOptions.direction = [0, 0, -model.ellipse3MinRad * 1.2]; - linearOptions.labelSize = 3; - linearOptions.labelOffset = 3; - linearOptions.crossingSize = 1; - linearOptions.labelSuffix = '(m)'; - const dimLength = await dimensions.simpleLinearLengthDimension(linearOptions); - shapesToClean.push(dimLength); - - linearOptions.start = [0, 0.01, model.ellipse3MinRad]; - linearOptions.end = [0, 0.01, -model.ellipse3MinRad]; - linearOptions.direction = [-model.ellipse3MaxRad * 1.2, 0, 0]; - const dimWidth = await dimensions.simpleLinearLengthDimension(linearOptions); - shapesToClean.push(dimWidth); - - linearOptions.labelOffset = 1; - linearOptions.start = [0, model.height, 0]; - linearOptions.end = [0, 0, 0]; - linearOptions.offsetFromPoints = model.ellipse3MaxRad; - linearOptions.direction = [model.ellipse3MaxRad * 1.05, 0, 0]; - linearOptions.labelSize = 1; - const dimHeight = await dimensions.simpleLinearLengthDimension(linearOptions); - shapesToClean.push(dimHeight); - - linearOptions.start = [0, bbox.max[1], 0]; - linearOptions.end = [0, 0, 0]; - linearOptions.offsetFromPoints = model.ellipse3MaxRad; - linearOptions.direction = [model.ellipse3MaxRad * 1.1, 0, 0]; - linearOptions.labelSize = 1; - const dimHeight2 = await dimensions.simpleLinearLengthDimension( - linearOptions - ); - shapesToClean.push(dimHeight2); - - const pinOpt = new Inputs.OCCT.PinWithLabelDto(); - pinOpt.startPoint = [0, 0, 0]; - pinOpt.endPoint = [0, model.height * 2, -model.ellipse2MaxRad / 2]; - pinOpt.direction = [0, 0, -4]; - pinOpt.label = `Nr Hexagons ${model.uHex * model.vHex}`; - pinOpt.labelSize = 2; - pinOpt.labelOffset = 3; - const pointerDim = await dimensions.pinWithLabel(pinOpt); - shapesToClean.push(pointerDim); - - const shapesDimCompound = [ - dimLength, - dimWidth, - dimHeight, - dimHeight2, - pointerDim, - ]; - - if (model.ellipse2RotX) { - const angleOpt = new Inputs.OCCT.SimpleAngularDimensionDto(); - angleOpt.center = [0, model.height, 0]; - const rotPts = bitbybit.point.rotatePointsCenterAxis({ - points: [[1, 0, 0]], - center: [0, 0, 0], - axis: [0, 0, -1], - angle: model.ellipse2RotX, - }); - angleOpt.direction1 = rotPts[0]; - angleOpt.direction2 = [model.ellipse3MaxRad, 0, 0]; - angleOpt.radius = model.ellipse2MaxRad * 0.7; - angleOpt.offsetFromCenter = 0; - angleOpt.extraSize = 1; - angleOpt.labelSize = 1; - angleOpt.labelOffset = 2; - - const angleDim = await dimensions.simpleAngularDimension(angleOpt); - shapesToClean.push(angleDim); - const rotAngleDim = await bitbybit.occt.transforms.rotate({ - shape: angleDim, - axis: [0, 1, 0], - angle: -model.ellipse2RotY, - }); - shapesToClean.push(rotAngleDim); - shapesDimCompound.push(rotAngleDim); - } - - const dimCompound = await shapes.compound.makeCompound({ - shapes: shapesDimCompound, - }); - shapesToClean.push(dimCompound); - - const rotCompound = await bitbybit.occt.transforms.rotate({ - shape: dimCompound, - axis: [0, 1, 0], - angle: -model.ellipse3YRot, - }); - - shapesToClean.push(rotCompound); - const compWithWires = await bitbybit.occt.shapes.compound.makeCompound({ - shapes: [...wires, rotCompound], - }); - return compWithWires; -} diff --git a/examples/vite/threejs/hex-shell/src/helpers/create-gui.ts b/examples/vite/threejs/hex-shell/src/helpers/create-gui.ts new file mode 100644 index 00000000..fa3e716b --- /dev/null +++ b/examples/vite/threejs/hex-shell/src/helpers/create-gui.ts @@ -0,0 +1,98 @@ +import GUI from "lil-gui"; +import type { Current, Model } from "../models"; +import type { Mesh, MeshPhongMaterial } from "three"; + +export const createGui = ( + current: Current, + model: Model, + updateShape: (lod: boolean) => void +) => { + model.update = () => updateShape(true); + const gui = new GUI(); + current.gui = gui; + gui.$title.innerHTML = "Pattern"; + + gui + .add(model, "uHex", 1, 14, 1) + .name("Hexagons U") + .onFinishChange((value: number) => { + model.uHex = value; + updateShape(false); + }); + + gui + .add(model, "vHex", 8, 36, 2) + .name("Hexagons V") + .onFinishChange((value: number) => { + model.vHex = value; + updateShape(false); + }); + + gui + .add(model, "height", 15, 25, 1) + .name("Height") + .onFinishChange((value: number) => { + model.height = value; + updateShape(false); + }); + + gui + .add(model, "ellipse2RotX", 0, 15, 0.1) + .name("Angle Guide") + .onFinishChange((value: number) => { + model.ellipse2RotX = value; + updateShape(false); + }); + + gui + .add(model, "finalPrecision", 0.01, 1, 0.01) + .name("Final Precision") + .onFinishChange((value: number) => { + model.finalPrecision = value; + }); + + gui + .add(model, "rotationEnabled") + .name("Rotation Enabled") + .onFinishChange((value: boolean) => { + model.rotationEnabled = value; + }); + + gui + .add(model, "drawEdges") + .name("Draw Edges") + .onFinishChange((value: boolean) => { + model.drawEdges = value; + }); + + gui + .addColor(model, "color1") + .name("Color 1") + .onChange((value: string) => { + current.group1?.children.forEach((group) => { + const children = group?.children[0].children as Mesh[]; + [...children].forEach((child) => { + const material = (child as Mesh).material as MeshPhongMaterial; + material.color.setHex(parseInt(value.replace("#", "0x"))); + }); + }); + }); + + gui + .addColor(model, "color2") + .name("Color 2") + .onChange((value: string) => { + current.group2?.children.forEach((group) => { + const children = group?.children[0].children as Mesh[]; + [...children].forEach((child) => { + const material = (child as Mesh).material as MeshPhongMaterial; + material.color.setHex(parseInt(value.replace("#", "0x"))); + }); + }); + }); + + gui.add(model, "update").name("Finalize"); + gui.add(model, "downloadSTL").name("Download STL"); + gui.add(model, "downloadStep").name("Download STEP"); + gui.add(model, "downloadGLB").name("Download GLB"); +}; diff --git a/examples/vite/threejs/hex-shell/src/helpers/create-shape.ts b/examples/vite/threejs/hex-shell/src/helpers/create-shape.ts new file mode 100644 index 00000000..5f2c1893 --- /dev/null +++ b/examples/vite/threejs/hex-shell/src/helpers/create-shape.ts @@ -0,0 +1,657 @@ +import type { BitByBitBase } from "@bitbybit-dev/threejs"; +import { Inputs } from "@bitbybit-dev/threejs"; +import { Color, DoubleSide, Group, MeshPhongMaterial, Scene } from "three"; +import type { Current, Model } from "../models"; + +export const createShapeLod2 = async ( + bitbybit: BitByBitBase | undefined, + scene: Scene | undefined, + model: Model, + shapesToClean: Inputs.OCCT.TopoDSShapePointer[], + current: Current +) => { + if (scene && bitbybit) { + if (shapesToClean.length > 0) { + await bitbybit.occt.deleteShapes({ shapes: shapesToClean }); + } + if (shapesToClean.length > 0) { + await bitbybit.occt.deleteShapes({ shapes: shapesToClean }); + } + + const { loft } = await createFaceAndEllipses(bitbybit, model); + shapesToClean.push(loft); + const faces = await bitbybit.occt.shapes.face.getFaces({ + shape: loft, + }); + + const faceBase = faces[0]; + shapesToClean.push(faceBase); + + const getFace = (l: Inputs.OCCT.TopoDSShapePointer) => { + return bitbybit.occt.shapes.face.getFace({ shape: l, index: 0 }); + }; + + const loft1 = await bitbybit.occt.operations.offset({ + shape: faceBase, + distance: -1.5, + tolerance: 1e-6, + }); + shapesToClean.push(loft1); + + const face1 = await getFace(loft1); + shapesToClean.push(face1); + + const loft3 = await bitbybit.occt.operations.offset({ + shape: faceBase, + distance: 1.5, + tolerance: 1e-6, + }); + shapesToClean.push(loft3); + + const loft4 = await bitbybit.occt.operations.offset({ + shape: faceBase, + distance: 3, + tolerance: 1e-6, + }); + shapesToClean.push(loft4); + + const loft5 = await bitbybit.occt.operations.offset({ + shape: faceBase, + distance: 5, + tolerance: 1e-6, + }); + shapesToClean.push(loft5); + + const face2 = faceBase; + const face3 = await getFace(loft3); + const face4 = await getFace(loft4); + const face5 = await getFace(loft5); + shapesToClean.push(face3); + shapesToClean.push(face4); + shapesToClean.push(face5); + + const subdivideOptions = new Inputs.OCCT.FaceSubdivideToHexagonWiresDto( + face1 + ); + subdivideOptions.nrHexagonsU = model.vHex; + subdivideOptions.nrHexagonsV = model.uHex; + subdivideOptions.extendUUp = true; + subdivideOptions.filletPattern = [0.8]; + subdivideOptions.scalePatternU = [0.4, 0.3, 0.2]; + subdivideOptions.scalePatternV = [0.4, 0.3, 0.2]; + const thickness = 0.1; + const wrs1Out = await bitbybit.occt.shapes.face.subdivideToHexagonWires( + subdivideOptions + ); + subdivideOptions.scalePatternU = [ + 0.4 - thickness, + 0.3 - thickness, + 0.2 - thickness, + ]; + subdivideOptions.scalePatternV = [ + 0.4 - thickness, + 0.3 - thickness, + 0.2 - thickness, + ]; + shapesToClean.push(...wrs1Out); + + const wrs1In = await bitbybit.occt.shapes.face.subdivideToHexagonWires( + subdivideOptions + ); + shapesToClean.push(...wrs1In); + + subdivideOptions.scalePatternU = [1]; + subdivideOptions.scalePatternV = [1]; + subdivideOptions.filletPattern = [0.001]; + subdivideOptions.shape = face2; + const wrs2Out = await bitbybit.occt.shapes.face.subdivideToHexagonWires( + subdivideOptions + ); + shapesToClean.push(...wrs2Out); + + subdivideOptions.filletPattern = [0.8]; + subdivideOptions.scalePatternU = [0.4]; + subdivideOptions.scalePatternV = [0.4]; + const wrs2In = await bitbybit.occt.shapes.face.subdivideToHexagonWires( + subdivideOptions + ); + shapesToClean.push(...wrs2In); + + subdivideOptions.scalePatternU = [0.98]; + subdivideOptions.scalePatternV = [0.98]; + subdivideOptions.shape = face3; + subdivideOptions.filletPattern = [0.001]; + const wrs3Out = await bitbybit.occt.shapes.face.subdivideToHexagonWires( + subdivideOptions + ); + shapesToClean.push(...wrs3Out); + + subdivideOptions.scalePatternU = [0.4]; + subdivideOptions.scalePatternV = [0.4]; + subdivideOptions.filletPattern = [0.9]; + const wrs3In = await bitbybit.occt.shapes.face.subdivideToHexagonWires( + subdivideOptions + ); + shapesToClean.push(...wrs3In); + + subdivideOptions.scalePatternU = [1]; + subdivideOptions.scalePatternV = [1]; + subdivideOptions.filletPattern = [0.001]; + subdivideOptions.shape = face4; + const wrs4Out = await bitbybit.occt.shapes.face.subdivideToHexagonWires( + subdivideOptions + ); + shapesToClean.push(...wrs4Out); + + subdivideOptions.scalePatternU = [0.3]; + subdivideOptions.scalePatternV = [0.3]; + subdivideOptions.filletPattern = [0.8]; + const wrs4In = await bitbybit.occt.shapes.face.subdivideToHexagonWires( + subdivideOptions + ); + shapesToClean.push(...wrs4In); + + subdivideOptions.scalePatternU = [0.9]; + subdivideOptions.scalePatternV = [0.9]; + subdivideOptions.filletPattern = [0.3]; + const wrs4InSpec = await bitbybit.occt.shapes.face.subdivideToHexagonWires( + subdivideOptions + ); + shapesToClean.push(...wrs4InSpec); + + subdivideOptions.scalePatternU = [0.4, 0.3, 0.2]; + subdivideOptions.scalePatternV = [0.4, 0.3, 0.2]; + subdivideOptions.shape = face5; + subdivideOptions.filletPattern = [0.9]; + const wrs5Out = await bitbybit.occt.shapes.face.subdivideToHexagonWires( + subdivideOptions + ); + shapesToClean.push(...wrs5Out); + + subdivideOptions.scalePatternU = [ + 0.4 - thickness, + 0.3 - thickness, + 0.2 - thickness, + ]; + subdivideOptions.scalePatternV = [ + 0.4 - thickness, + 0.3 - thickness, + 0.2 - thickness, + ]; + subdivideOptions.filletPattern = [0.9]; + + const wrs5In = await bitbybit.occt.shapes.face.subdivideToHexagonWires( + subdivideOptions + ); + shapesToClean.push(...wrs5In); + + const loftPromises: Promise[] = []; + const loftOptions = + new Inputs.OCCT.LoftAdvancedDto(); + loftOptions.straight = true; + loftOptions.closed = true; + + const indexes1: number[] = []; + const indexes2: number[] = []; + wrs1Out.forEach((w1Out, index) => { + const w1In = wrs1In[index]; + const w2Out = wrs2Out[index]; + const w2In = wrs2In[index]; + const w3Out = wrs3Out[index]; + const w3In = wrs3In[index]; + const w4Out = wrs4Out[index]; + const w4In = wrs4In[index]; + const w4InSpec = wrs4InSpec[index]; + const w5Out = wrs5Out[index]; + const w5In = wrs5In[index]; + + if (index % 3 === 0) { + indexes1.push(index); + loftOptions.shapes = [ + w1In, + w2In, + w3In, + w4In, + w5In, + w5Out, + w4Out, + w3Out, + w2Out, + w1Out, + ].reverse(); + } else { + indexes2.push(index); + loftOptions.shapes = [ + w2In, + w3In, + w4InSpec, + w4Out, + w3Out, + w2Out, + ].reverse(); + } + + const lft = bitbybit.occt.operations.loftAdvanced(loftOptions); + loftPromises.push(lft); + }); + + const lofts: Inputs.OCCT.TopoDSShapePointer[] = await Promise.all( + loftPromises + ); + shapesToClean.push(...lofts); + const lofts1: Inputs.OCCT.TopoDSShapePointer[] = indexes1.map( + (i) => lofts[i] + ); + const lofts2: Inputs.OCCT.TopoDSShapePointer[] = indexes2.map( + (i) => lofts[i] + ); + + const chunkSize = 40; + const lofts1Chunked = bitbybit.lists.groupNth({ + list: lofts1, + nrElements: chunkSize, + keepRemainder: true, + }); + const lofts2Chunked = bitbybit.lists.groupNth({ + list: lofts2, + nrElements: chunkSize, + keepRemainder: true, + }); + + const compounds1ToDrawPromises = lofts1Chunked.map((lchunk) => + bitbybit.occt.shapes.compound.makeCompound({ + shapes: lchunk, + }) + ); + + const compounds2ToDrawPromises = lofts2Chunked.map((lchunk) => + bitbybit.occt.shapes.compound.makeCompound({ + shapes: lchunk, + }) + ); + + const compounds1ToDraw = await Promise.all(compounds1ToDrawPromises); + const compounds2ToDraw = await Promise.all(compounds2ToDrawPromises); + + shapesToClean.push(...compounds1ToDraw); + shapesToClean.push(...compounds2ToDraw); + + const finalShape = await bitbybit.occt.shapes.compound.makeCompound({ + shapes: [...lofts1, ...lofts2], + }); + + shapesToClean.push(finalShape); + + // DRAWING BEGINS + + const options = new Inputs.Draw.DrawOcctShapeOptions(); + options.precision = model.finalPrecision; + options.drawEdges = model.drawEdges; + options.drawFaces = model.drawFaces; + options.drawVertices = false; + options.edgeWidth = 20; + options.edgeColour = "#000000"; + + const mat = new MeshPhongMaterial({ color: new Color(model.color1) }); + if (model.drawEdges) { + mat.polygonOffset = true; + mat.polygonOffsetFactor = 1; + } + options.faceMaterial = mat; + + const groups1Promises = compounds1ToDraw.map((comp) => + bitbybit.draw.drawAnyAsync({ entity: comp, options }) + ); + + const mat2 = new MeshPhongMaterial({ color: new Color(model.color2) }); + if (model.drawEdges) { + mat2.polygonOffset = true; + mat2.polygonOffsetFactor = 1; + } + options.faceMaterial = mat2; + + const groups2Promises = compounds2ToDraw.map((comp) => + bitbybit.draw.drawAnyAsync({ entity: comp, options }) + ); + + const groups1 = await Promise.all(groups1Promises); + const groups2 = await Promise.all(groups2Promises); + + const group1 = new Group(); + group1.add(...groups1); + scene.add(group1); + + const group2 = new Group(); + group2.add(...groups2); + scene.add(group2); + + groups1.forEach((group) => { + group.children[0].children.forEach((child) => { + child.castShadow = true; + child.receiveShadow = true; + }); + }); + + groups2.forEach((group) => { + group.children[0].children.forEach((child) => { + child.castShadow = true; + child.receiveShadow = true; + }); + }); + + current.group1 = group1; + current.group2 = group2; + return finalShape; + } +}; + +export const createShapeLod1 = async ( + bitbybit: BitByBitBase | undefined, + scene: Scene | undefined, + model: Model, + shapesToClean: Inputs.OCCT.TopoDSShapePointer[], + current: Current +) => { + if (scene && bitbybit) { + if (shapesToClean.length > 0) { + await bitbybit.occt.deleteShapes({ shapes: shapesToClean }); + } + if (shapesToClean.length > 0) { + await bitbybit.occt.deleteShapes({ shapes: shapesToClean }); + } + + const { loft, w1, w2, w3 } = await createFaceAndEllipses(bitbybit, model); + shapesToClean.push(loft, w1, w2, w3); + const faces = await bitbybit.occt.shapes.face.getFaces({ + shape: loft, + }); + + const faceBase = faces[0]; + shapesToClean.push(faceBase); + + const subdivideOptions = new Inputs.OCCT.FaceSubdivideToHexagonWiresDto( + faceBase + ); + subdivideOptions.nrHexagonsU = model.vHex; + subdivideOptions.nrHexagonsV = model.uHex; + subdivideOptions.extendUUp = true; + const wrs1Out = await bitbybit.occt.shapes.face.subdivideToHexagonWires( + subdivideOptions + ); + shapesToClean.push(...wrs1Out); + + const fcs: Inputs.OCCT.TopoDSFacePointer[] = + (await bitbybit.occt.shapes.face.createFacesFromWiresOnFace({ + wires: wrs1Out, + face: faceBase, + inside: true, + })) as any; + + shapesToClean.push(...fcs); + const firstGroupFcs: Inputs.OCCT.TopoDSFacePointer[] = []; + const secondGroupFcs: Inputs.OCCT.TopoDSFacePointer[] = []; + fcs.forEach((f, index) => { + if (index % 3 === 0) { + firstGroupFcs.push(f); + } else { + secondGroupFcs.push(f); + } + }); + + const firstGroup = await bitbybit.occt.shapes.compound.makeCompound({ + shapes: firstGroupFcs, + }); + shapesToClean.push(firstGroup); + const secondGroup = await bitbybit.occt.shapes.compound.makeCompound({ + shapes: secondGroupFcs, + }); + shapesToClean.push(secondGroup); + + const dimensions = await createDimensions( + bitbybit, + model, + faceBase, + [w1, w2, w3], + shapesToClean + ); + + shapesToClean.push(dimensions); + + const options = new Inputs.Draw.DrawOcctShapeOptions(); + options.precision = 0.01; + options.drawEdges = true; + options.drawFaces = true; + options.drawVertices = false; + options.edgeWidth = 20; + + options.edgeColour = "#ffffff"; + + const mat = new MeshPhongMaterial({ color: new Color(model.color1) }); + mat.polygonOffset = true; + mat.polygonOffsetFactor = 1; + mat.transparent = true; + mat.opacity = 0.5; + mat.side = DoubleSide; + options.faceMaterial = mat; + const grp1 = await bitbybit.draw.drawAnyAsync({ + entity: firstGroup, + options, + }); + + const mat2 = new MeshPhongMaterial({ color: new Color(model.color2) }); + mat2.polygonOffset = true; + mat2.polygonOffsetFactor = 1; + mat2.transparent = true; + mat2.opacity = 0.5; + mat2.side = DoubleSide; + options.faceMaterial = mat2; + const grp2 = await bitbybit.draw.drawAnyAsync({ + entity: secondGroup, + options, + }); + + grp1.children[0].children.forEach((child) => { + child.castShadow = true; + child.receiveShadow = true; + }); + + grp2.children[0].children.forEach((child) => { + child.castShadow = true; + child.receiveShadow = true; + }); + + const dimOpt = new Inputs.Draw.DrawOcctShapeOptions(); + dimOpt.edgeColour = "#aaaaff"; + dimOpt.drawFaces = false; + const dimensionsGroup = await bitbybit.draw.drawAnyAsync({ + entity: dimensions, + options: dimOpt, + }); + dimensionsGroup.position.y = 0.02; + + // just to match chunked data structure of LOD2 + const group1 = new Group(); + group1.add(grp1); + scene.add(group1); + const group2 = new Group(); + group2.add(grp2); + scene.add(group2); + + current.group1 = group1; + current.group2 = group2; + current.dimensions = dimensionsGroup; + + const finalShape = await bitbybit.occt.shapes.compound.makeCompound({ + shapes: [firstGroup, secondGroup, dimensions], + }); + + return finalShape; + } +}; + +async function createFaceAndEllipses(bitbybit: BitByBitBase, model: Model) { + const ellipseOptions = new Inputs.OCCT.EllipseDto(); + const { wire } = bitbybit.occt.shapes; + const { transforms, operations } = bitbybit.occt; + + ellipseOptions.radiusMinor = model.ellipse1MinRad; + ellipseOptions.radiusMajor = model.ellipse1MaxRad; + const w1 = await wire.createEllipseWire(ellipseOptions); + + ellipseOptions.radiusMinor = model.ellipse2MinRad; + ellipseOptions.radiusMajor = model.ellipse2MaxRad; + const w2s = await wire.createEllipseWire(ellipseOptions); + + let w2r1; + if (model.ellipse2RotX > 0) { + w2r1 = await transforms.rotate({ + shape: w2s, + angle: model.ellipse2RotX, + axis: [1, 0, 0], + }); + } else { + w2r1 = w2s; + } + + const w2r2 = await transforms.rotate({ + shape: w2r1, + angle: model.ellipse2RotY, + axis: [0, 1, 0], + }); + const w2 = await transforms.translate({ + shape: w2r2, + translation: [0, model.height, 0], + }); + + ellipseOptions.radiusMinor = model.ellipse3MinRad; + ellipseOptions.radiusMajor = model.ellipse3MaxRad; + const w3s = await wire.createEllipseWire(ellipseOptions); + const w3 = await transforms.rotate({ + shape: w3s, + angle: model.ellipse3YRot, + axis: [0, 1, 0], + }); + const loft = await operations.loft({ + shapes: [w3, w2, w1], + makeSolid: false, + }); + + return { loft, w1, w2, w3 }; +} + +async function createDimensions( + bitbybit: BitByBitBase, + model: Model, + faceBase: Inputs.OCCT.TopoDSFacePointer, + wires: Inputs.OCCT.TopoDSWirePointer[], + shapesToClean: Inputs.OCCT.TopoDSShapePointer[] +) { + const subOpt = + new Inputs.OCCT.FaceSubdivisionDto(); + subOpt.shape = faceBase; + subOpt.nrDivisionsU = 50; + subOpt.nrDivisionsV = 50; + const pts = await bitbybit.occt.shapes.face.subdivideToPoints(subOpt); + const bbox = bitbybit.point.boundingBoxOfPoints({ points: pts }); + + const { dimensions, shapes } = bitbybit.occt; + const linearOptions = new Inputs.OCCT.SimpleLinearLengthDimensionDto(); + + linearOptions.start = [-model.ellipse3MaxRad, 0.01, 0]; + linearOptions.end = [model.ellipse3MaxRad, 0.01, 0]; + linearOptions.direction = [0, 0, -model.ellipse3MinRad * 1.2]; + linearOptions.labelSize = 3; + linearOptions.labelOffset = 3; + linearOptions.crossingSize = 1; + linearOptions.labelSuffix = "(m)"; + const dimLength = await dimensions.simpleLinearLengthDimension(linearOptions); + shapesToClean.push(dimLength); + + linearOptions.start = [0, 0.01, model.ellipse3MinRad]; + linearOptions.end = [0, 0.01, -model.ellipse3MinRad]; + linearOptions.direction = [-model.ellipse3MaxRad * 1.2, 0, 0]; + const dimWidth = await dimensions.simpleLinearLengthDimension(linearOptions); + shapesToClean.push(dimWidth); + + linearOptions.labelOffset = 1; + linearOptions.start = [0, model.height, 0]; + linearOptions.end = [0, 0, 0]; + linearOptions.offsetFromPoints = model.ellipse3MaxRad; + linearOptions.direction = [model.ellipse3MaxRad * 1.05, 0, 0]; + linearOptions.labelSize = 1; + const dimHeight = await dimensions.simpleLinearLengthDimension(linearOptions); + shapesToClean.push(dimHeight); + + linearOptions.start = [0, bbox.max[1], 0]; + linearOptions.end = [0, 0, 0]; + linearOptions.offsetFromPoints = model.ellipse3MaxRad; + linearOptions.direction = [model.ellipse3MaxRad * 1.1, 0, 0]; + linearOptions.labelSize = 1; + const dimHeight2 = await dimensions.simpleLinearLengthDimension( + linearOptions + ); + shapesToClean.push(dimHeight2); + + const pinOpt = new Inputs.OCCT.PinWithLabelDto(); + pinOpt.startPoint = [0, 0, 0]; + pinOpt.endPoint = [0, model.height * 2, -model.ellipse2MaxRad / 2]; + pinOpt.direction = [0, 0, -4]; + pinOpt.label = `Nr Hexagons ${model.uHex * model.vHex}`; + pinOpt.labelSize = 2; + pinOpt.labelOffset = 3; + const pointerDim = await dimensions.pinWithLabel(pinOpt); + shapesToClean.push(pointerDim); + + const shapesDimCompound = [ + dimLength, + dimWidth, + dimHeight, + dimHeight2, + pointerDim, + ]; + + if (model.ellipse2RotX) { + const angleOpt = new Inputs.OCCT.SimpleAngularDimensionDto(); + angleOpt.center = [0, model.height, 0]; + const rotPts = bitbybit.point.rotatePointsCenterAxis({ + points: [[1, 0, 0]], + center: [0, 0, 0], + axis: [0, 0, -1], + angle: model.ellipse2RotX, + }); + angleOpt.direction1 = rotPts[0]; + angleOpt.direction2 = [model.ellipse3MaxRad, 0, 0]; + angleOpt.radius = model.ellipse2MaxRad * 0.7; + angleOpt.offsetFromCenter = 0; + angleOpt.extraSize = 1; + angleOpt.labelSize = 1; + angleOpt.labelOffset = 2; + + const angleDim = await dimensions.simpleAngularDimension(angleOpt); + shapesToClean.push(angleDim); + const rotAngleDim = await bitbybit.occt.transforms.rotate({ + shape: angleDim, + axis: [0, 1, 0], + angle: -model.ellipse2RotY, + }); + shapesToClean.push(rotAngleDim); + shapesDimCompound.push(rotAngleDim); + } + + const dimCompound = await shapes.compound.makeCompound({ + shapes: shapesDimCompound, + }); + shapesToClean.push(dimCompound); + + const rotCompound = await bitbybit.occt.transforms.rotate({ + shape: dimCompound, + axis: [0, 1, 0], + angle: -model.ellipse3YRot, + }); + + shapesToClean.push(rotCompound); + const compWithWires = await bitbybit.occt.shapes.compound.makeCompound({ + shapes: [...wires, rotCompound], + }); + return compWithWires; +} diff --git a/examples/vite/threejs/hex-shell/src/helpers/downloads.ts b/examples/vite/threejs/hex-shell/src/helpers/downloads.ts new file mode 100644 index 00000000..2f870e9b --- /dev/null +++ b/examples/vite/threejs/hex-shell/src/helpers/downloads.ts @@ -0,0 +1,62 @@ +import type { BitByBitBase, Inputs } from "@bitbybit-dev/threejs"; +import type { Scene } from "three"; +import { STLExporter } from "three/examples/jsm/exporters/STLExporter"; +import { GLTFExporter } from "three/examples/jsm/exporters/GLTFExporter"; + +export const downloadStep = async ( + bitbybit: BitByBitBase, + finalShape: Inputs.OCCT.TopoDSShapePointer | undefined +) => { + if (bitbybit && finalShape) { + // threejs is right handed - originally bitbybit was built on left handed system, thus this compensation is needed till + // we improve support + const exportShape = await bitbybit.occt.transforms.mirrorAlongNormal({ + shape: finalShape, + origin: [0, 0, 0], + normal: [0, 0, 1], + }); + await bitbybit.occt.io.saveShapeSTEP({ + shape: exportShape, + fileName: "shape", + adjustYtoZ: true, + tryDownload: true, + }); + bitbybit.occt.deleteShape({ shape: exportShape }); + } +}; + +export const downloadSTL = (scene: Scene) => { + if (scene) { + var exporter = new STLExporter(); + var str = exporter.parse(scene); + var blob = new Blob([str], { type: "text/plain" }); + var link = document.createElement("a"); + link.style.display = "none"; + document.body.appendChild(link); + link.href = URL.createObjectURL(blob); + link.download = "Scene.stl"; + link.click(); + } +}; + +export const downloadGLB = (scene: Scene) => { + if (scene) { + var exporter = new GLTFExporter(); + exporter.parse( + scene, + function (gltf: ArrayBuffer) { + var blob = new Blob([gltf], { type: "application/octet-stream" }); + var link = document.createElement("a"); + link.style.display = "none"; + document.body.appendChild(link); + link.href = URL.createObjectURL(blob); + link.download = "Scene.glb"; + link.click(); + }, + function (error: string) { + console.error("An error happened", error); + }, + { trs: false, onlyVisible: true, binary: true } + ); + } +}; diff --git a/examples/vite/threejs/hex-shell/src/helpers/gui-helper.ts b/examples/vite/threejs/hex-shell/src/helpers/gui-helper.ts new file mode 100644 index 00000000..c8f967e8 --- /dev/null +++ b/examples/vite/threejs/hex-shell/src/helpers/gui-helper.ts @@ -0,0 +1,31 @@ +export function disableGUI() { + const lilGui = document.getElementsByClassName("lil-gui")[0] as HTMLElement; + lilGui.style.pointerEvents = "none"; + lilGui.style.opacity = "0.5"; +} + +export function enableGUI() { + const lilGui = document.getElementsByClassName("lil-gui")[0] as HTMLElement; + lilGui.style.pointerEvents = "all"; + lilGui.style.opacity = "1"; +} + +export function showSpinner() { + const element = document.createElement("div"); + element.id = "spinner"; + element.className = "lds-ellipsis"; + element.innerHTML = ` +
+
+
+`; + + document.body.appendChild(element); +} + +export function hideSpinner() { + const el = document.getElementById("spinner"); + if (el) { + el.remove(); + } +} diff --git a/examples/vite/threejs/hex-shell/src/helpers/index.ts b/examples/vite/threejs/hex-shell/src/helpers/index.ts new file mode 100644 index 00000000..5d4584ba --- /dev/null +++ b/examples/vite/threejs/hex-shell/src/helpers/index.ts @@ -0,0 +1,7 @@ +export * from './create-gui'; +export * from './create-shape'; +export * from './init-kernels'; +export * from './init-threejs'; +export * from './downloads'; +export * from './gui-helper'; +export * from './downloads'; diff --git a/examples/vite/threejs/hex-shell/src/helpers/init-kernels.ts b/examples/vite/threejs/hex-shell/src/helpers/init-kernels.ts new file mode 100644 index 00000000..0667cc8b --- /dev/null +++ b/examples/vite/threejs/hex-shell/src/helpers/init-kernels.ts @@ -0,0 +1,125 @@ +import type { BitByBitBase } from "@bitbybit-dev/threejs"; +import type { Scene } from "three"; +import type { KernelOptions } from "../models"; +import { first, firstValueFrom, tap } from "rxjs"; +import { OccStateEnum } from "@bitbybit-dev/occt-worker"; +import { JscadStateEnum } from "@bitbybit-dev/jscad-worker"; +import { ManifoldStateEnum } from "@bitbybit-dev/manifold-worker"; + +export async function initKernels( + scene: Scene, + bitbybit: BitByBitBase, + options: KernelOptions +): Promise<{ message: string }> { + let occtWorkerInstance: Worker | undefined; + let jscadWorkerInstance: Worker | undefined; + let manifoldWorkerInstance: Worker | undefined; + + // 1. Conditionally create worker instances + if (options.enableOCCT) { + occtWorkerInstance = new Worker( + new URL("../workers/occt.worker.ts", import.meta.url), + { name: "OCC_WORKER", type: "module" } + ); + } + if (options.enableJSCAD) { + jscadWorkerInstance = new Worker( + new URL("../workers/jscad.worker.ts", import.meta.url), + { name: "JSCAD_WORKER", type: "module" } + ); + } + if (options.enableManifold) { + manifoldWorkerInstance = new Worker( + new URL("../workers/manifold.worker.ts", import.meta.url), + { name: "MANIFOLD_WORKER", type: "module" } + ); + } + + // 2. Initialize Bitbybit + await bitbybit.init( + scene, + occtWorkerInstance, + jscadWorkerInstance, + manifoldWorkerInstance + ); + + // 3. Collect promises for kernel initializations + const initializationPromises: Promise[] = []; + let anyKernelSelectedForInit = false; + + if (options.enableOCCT) { + anyKernelSelectedForInit = true; + if (bitbybit.occtWorkerManager) { + initializationPromises.push( + firstValueFrom( + bitbybit.occtWorkerManager.occWorkerState$.pipe( + first((s) => s.state === OccStateEnum.initialised), + tap(() => console.log("OCCT Initialized")) + ) + ).then(() => { }) // Ensure the promise resolves to void for Promise.all + ); + } else { + console.warn( + "OCCT enabled in options, but occtWorkerManager not found after init." + ); + } + } + + if (options.enableJSCAD) { + anyKernelSelectedForInit = true; + if (bitbybit.jscadWorkerManager) { + initializationPromises.push( + firstValueFrom( + bitbybit.jscadWorkerManager.jscadWorkerState$.pipe( + first((s) => s.state === JscadStateEnum.initialised), + tap(() => console.log("JSCAD Initialized")) + ) + ).then(() => { }) + ); + } else { + console.warn( + "JSCAD enabled in options, but jscadWorkerManager not found after init." + ); + } + } + + if (options.enableManifold) { + anyKernelSelectedForInit = true; + if (bitbybit.manifoldWorkerManager) { + initializationPromises.push( + firstValueFrom( + bitbybit.manifoldWorkerManager.manifoldWorkerState$.pipe( + first((s) => s.state === ManifoldStateEnum.initialised), + tap(() => console.log("Manifold Initialized")) + ) + ).then(() => { }) + ); + } else { + console.warn( + "Manifold enabled in options, but manifoldWorkerManager not found after init." + ); + } + } + + // 4. Wait for selected & available kernels or handle no selection/availability + if (!anyKernelSelectedForInit) { + console.log("No kernels selected for initialization."); + return { message: "No kernels selected for initialization." }; + } + + if (initializationPromises.length === 0) { + // Kernels were selected, but none were awaitable (e.g., managers missing for all selected) + console.log( + "Kernels were selected, but none had managers available for awaiting initialization." + ); + return { + message: "Selected kernels were not awaitable for initialization state.", + }; + } + + await Promise.all(initializationPromises); + console.log("Selected and awaitable kernels initialized:", options); + return { + message: "Selected and awaitable kernels initialized successfully.", + }; +} diff --git a/examples/vite/threejs/hex-shell/src/helpers/init-threejs.ts b/examples/vite/threejs/hex-shell/src/helpers/init-threejs.ts new file mode 100644 index 00000000..bd0e7782 --- /dev/null +++ b/examples/vite/threejs/hex-shell/src/helpers/init-threejs.ts @@ -0,0 +1,109 @@ +import { + Color, + DirectionalLight, + Fog, + HemisphereLight, + Mesh, + MeshPhongMaterial, + PerspectiveCamera, + PlaneGeometry, + Scene, + VSMShadowMap, + WebGLRenderer, +} from "three"; +import { OrbitControls } from "three/examples/jsm/controls/OrbitControls"; +import type { Current } from "../models"; + +export function initThreeJS() { + const domNode = document.getElementById("three-canvas") as HTMLCanvasElement; + + const camera = new PerspectiveCamera( + 70, + window.innerWidth / window.innerHeight, + 0.1, // Adjusted near plane for typical scenes + 1000 + ); + const scene = new Scene(); + scene.background = new Color(0x1a1c1f); // Set background color + + scene.fog = new Fog(0x1a1c1f, 150, 230); + const light = new HemisphereLight(0xffffff, 0x444444, 2); // Adjusted intensity + scene.add(light); + + const renderer = new WebGLRenderer({ antialias: true, canvas: domNode }); + renderer.setSize(window.innerWidth, window.innerHeight); + renderer.setPixelRatio(window.devicePixelRatio / 1.5); // Consider devicePixelRatio for sharpness + renderer.shadowMap.enabled = true; + renderer.shadowMap.type = VSMShadowMap; + + camera.position.set(10, 5, 120); + camera.aspect = window.innerWidth / window.innerHeight; + camera.near = 3; + camera.far = 1000; + camera.updateProjectionMatrix(); + + const controls = new OrbitControls(camera, renderer.domElement); + controls.enableDamping = true; + controls.dampingFactor = 0.05; + controls.zoomSpeed = 0.1; + controls.target.set(0, 0, 0); + controls.update(); + + const onWindowResize = () => { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + renderer.setSize(window.innerWidth, window.innerHeight); + }; + window.addEventListener("resize", onWindowResize, false); + + const animate = () => { + controls.update(); // Important for damping + renderer.render(scene, camera); + }; + renderer.setAnimationLoop(animate); + + return { scene, camera, renderer }; // Return renderer and camera if needed elsewhere +} + +export function createDirLightsAndGround(scene: Scene, current: Current) { + const dirLight = new DirectionalLight(0xffffff, 3); + dirLight.position.set(70, 25, -70); + dirLight.castShadow = true; + dirLight.shadow.camera.near = 3; + dirLight.shadow.camera.far = 300; + const dist = 100; + dirLight.shadow.camera.right = dist; + dirLight.shadow.camera.left = -dist; + dirLight.shadow.camera.top = dist; + dirLight.shadow.camera.bottom = -dist; + dirLight.shadow.mapSize.width = 1024; + dirLight.shadow.mapSize.height = 1024; + dirLight.shadow.blurSamples = 3; + dirLight.shadow.radius = 2; + dirLight.shadow.bias = -0.0005; + + scene?.add(dirLight); + current.light1 = dirLight; + + const dirLight2 = new DirectionalLight(0xffffff, 2); + dirLight2.position.set(15, -40, -15); + dirLight2.shadow.camera.near = 3; + dirLight2.shadow.camera.far = 300; + dirLight2.shadow.camera.right = dist; + dirLight2.shadow.camera.left = -dist; + dirLight2.shadow.camera.top = dist; + dirLight2.shadow.camera.bottom = -dist; + + scene?.add(dirLight2); + + const material = new MeshPhongMaterial({ color: 0x444444 }); + material.shininess = 0; + material.specular = new Color(0x222222); + material.polygonOffset = true; + material.polygonOffsetFactor = 10; + const ground = new Mesh(new PlaneGeometry(740, 740, 1, 1), material); + ground.rotateX(-Math.PI / 2); + ground.receiveShadow = true; + current.ground = ground; + scene?.add(ground); +} diff --git a/examples/vite/threejs/hex-shell/src/main.ts b/examples/vite/threejs/hex-shell/src/main.ts index ebc1d623..763479ab 100644 --- a/examples/vite/threejs/hex-shell/src/main.ts +++ b/examples/vite/threejs/hex-shell/src/main.ts @@ -1,420 +1,102 @@ -import './style.css'; -import { BitByBitBase } from '@bitbybit-dev/threejs'; -import { OccStateEnum } from '@bitbybit-dev/occt-worker'; -import { Inputs } from '@bitbybit-dev/threejs'; -import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'; -import { STLExporter } from 'three/examples/jsm/exporters/STLExporter'; -import { GLTFExporter } from 'three/examples/jsm/exporters/GLTFExporter'; +import "./style.css"; +import { BitByBitBase, Inputs } from "@bitbybit-dev/threejs"; +import { model, type KernelOptions, current } from "./models"; import { - Color, - DirectionalLight, - Fog, - HemisphereLight, - Mesh, - MeshPhongMaterial, - PerspectiveCamera, - PlaneGeometry, - Scene, - Vector3, - VSMShadowMap, - WebGLRenderer, -} from 'three'; -import { GUI } from 'lil-gui'; -import { createShapeLod2, createShapeLod1 } from './create-shape'; -import type { Current } from './models/current'; -import type { Model } from './models/model'; - -document.querySelector('#app')!.innerHTML = ` - - -`; - -function component() { - let current: Current = { - group1: undefined, - group2: undefined, - dimensions: undefined, - ground: undefined, - light1: undefined, - gui: undefined, - }; - - const model = { - uHex: 3, - vHex: 12, - height: 15, - ellipse1MinRad: 15, - ellipse1MaxRad: 15, - ellipse2MinRad: 25, - ellipse2MaxRad: 30, - ellipse2RotX: 15, - ellipse2RotY: 15, - ellipse3MinRad: 45, - ellipse3MaxRad: 90, - ellipse3YRot: 45, - finalPrecision: 0.05, - drawEdges: false, - drawFaces: true, - rotationEnabled: false, - color1: '#b3ccff', - color2: '#ffffff', - } as Model; - - let shapesToClean: Inputs.OCCT.TopoDSShapePointer[] = []; - let finalShape: Inputs.OCCT.TopoDSShapePointer | undefined; - let bitbybit: BitByBitBase | undefined; - let scene: Scene | undefined; - - const rotationSpeed = 0.0005; - const rotateGroup = () => { - if ( - model.rotationEnabled && - current.group1 && - current.group2 && - current.dimensions - ) { - current.group1.rotation.y -= rotationSpeed; - current.group2.rotation.y -= rotationSpeed; - current.dimensions.rotation.y -= rotationSpeed; - } - }; - - const downloadStep = async () => { - if (bitbybit && finalShape) { - // threejs is right handed - originally bitbybit was built on left handed system, thus this compensation is needed till - // we improve support - const exportShape = await bitbybit.occt.transforms.mirrorAlongNormal({ - shape: finalShape, - origin: [0, 0, 0], - normal: [0, 0, 1], - }); - await bitbybit.occt.io.saveShapeSTEP({ - shape: exportShape, - fileName: 'shape', - adjustYtoZ: true, - tryDownload: true, - }); - bitbybit.occt.deleteShape({ shape: exportShape }); - } - }; - - const downloadSTL = () => { - if (scene) { - var exporter = new STLExporter(); - var str = exporter.parse(scene); - var blob = new Blob([str], { type: 'text/plain' }); - var link = document.createElement('a'); - link.style.display = 'none'; - document.body.appendChild(link); - link.href = URL.createObjectURL(blob); - link.download = 'Scene.stl'; - link.click(); - } - }; - - const downloadGLB = () => { - if (scene) { - var exporter = new GLTFExporter(); - exporter.parse( - scene, - function (gltf: ArrayBuffer) { - var blob = new Blob([gltf], { type: 'application/octet-stream' }); - var link = document.createElement('a'); - link.style.display = 'none'; - document.body.appendChild(link); - link.href = URL.createObjectURL(blob); - link.download = 'Scene.glb'; - link.click(); - }, - function (error: string) { - console.error('An error happened', error); - }, - { trs: false, onlyVisible: true, binary: true } - ); - } - }; + initKernels, + initThreeJS, + createGui, + createShapeLod1, + createShapeLod2, + createDirLightsAndGround, + disableGUI, + enableGUI, + hideSpinner, + showSpinner, + downloadGLB, + downloadSTL, + downloadStep, +} from "./helpers"; + +const kernelOptions: KernelOptions = { + enableOCCT: true, + enableJSCAD: false, + enableManifold: false, +}; + +start(); + +async function start() { + const { scene } = initThreeJS(); + createDirLightsAndGround(scene, current); + + const bitbybit = new BitByBitBase(); + await initKernels(scene, bitbybit, kernelOptions); + + let finalShape: Inputs.OCCT.TopoDSShapePointer | undefined; + let shapesToClean: Inputs.OCCT.TopoDSShapePointer[] = []; + + model.downloadStep = () => downloadStep(bitbybit, finalShape); + model.downloadGLB = () => downloadGLB(scene); + model.downloadSTL = () => downloadSTL(scene); + + createGui(current, model, updateShape); + + const rotationSpeed = 0.0005; + const rotateGroup = () => { + if ( + model.rotationEnabled && + current.group1 && + current.group2 && + current.dimensions + ) { + current.group1.rotation.y -= rotationSpeed; + current.group2.rotation.y -= rotationSpeed; + current.dimensions.rotation.y -= rotationSpeed; + } + }; - model.downloadGLB = downloadGLB; - model.downloadSTL = downloadSTL; - model.downloadStep = downloadStep; + scene.onBeforeRender = () => { + rotateGroup(); + }; - const updateShape = async (finish: boolean) => { - disableGUI(); - showSpinner(); - current.group1?.traverse((obj) => { - scene?.remove(obj); - }); - current.group2?.traverse((obj) => { - scene?.remove(obj); - }); - current.dimensions?.traverse((obj) => { - scene?.remove(obj); - }); - if (finish) { - finalShape = await createShapeLod2( + finalShape = await createShapeLod1( bitbybit, scene, model, shapesToClean, current - ); - } else { - finalShape = await createShapeLod1( - bitbybit, - scene, - model, - shapesToClean, - current - ); - } - hideSpinner(); - enableGUI(); - }; - - model.update = () => updateShape(true); - - const init = async () => { - bitbybit = new BitByBitBase(); - - const domNode = document.getElementById( - 'three-canvas' - ) as HTMLCanvasElement; - const occt = new Worker(new URL('./workers/occt.worker', import.meta.url), { - name: 'OCC', - type: 'module', - }); - - const camera = new PerspectiveCamera( - 70, - window.innerWidth / window.innerHeight, - 0.01, - 1000 ); - scene = new Scene(); - scene.fog = new Fog(0x1a1c1f, 150, 230); - const light = new HemisphereLight(0xffffff, 0x000000, 1); - scene.add(light); - await bitbybit.init(scene, occt, undefined); - - const renderer = new WebGLRenderer({ antialias: true, canvas: domNode }); - camera.aspect = window.innerWidth / window.innerHeight; - camera.near = 3; - camera.far = 1000; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); - renderer.setPixelRatio(window.devicePixelRatio / 1.5); - const animation = () => { - if (scene) { - renderer.render(scene, camera); - rotateGroup(); - } - controls.update(); - }; - - const controls = new OrbitControls(camera, renderer.domElement); - - camera.position.set(10, 5, 120); - - controls.update(); - controls.target = new Vector3(0, 5, 0); - controls.enableDamping = true; - controls.dampingFactor = 0.1; - controls.zoomSpeed = 0.1; - renderer.shadowMap.enabled = true; - renderer.shadowMap.type = VSMShadowMap; - - const onWindowResize = () => { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - renderer.setSize(window.innerWidth, window.innerHeight); - }; - window.addEventListener('resize', onWindowResize, false); - - renderer.setClearColor(new Color(0x1a1c1f), 1); - - bitbybit.occtWorkerManager.occWorkerState$.subscribe(async (s) => { - if (s.state === OccStateEnum.initialised) { - finalShape = await createShapeLod1( - bitbybit, - scene, - model, - shapesToClean, - current - ); - - renderer.setAnimationLoop(animation); - - const dirLight = new DirectionalLight(0xffffff, 3); - dirLight.position.set(70, 25, -70); - dirLight.castShadow = true; - dirLight.shadow.camera.near = 3; - dirLight.shadow.camera.far = 300; - const dist = 100; - dirLight.shadow.camera.right = dist; - dirLight.shadow.camera.left = -dist; - dirLight.shadow.camera.top = dist; - dirLight.shadow.camera.bottom = -dist; - dirLight.shadow.mapSize.width = 6000; - dirLight.shadow.mapSize.height = 6000; - dirLight.shadow.blurSamples = 3; - dirLight.shadow.radius = 2; - dirLight.shadow.bias = -0.0005; - - scene?.add(dirLight); - current.light1 = dirLight; - - const dirLight2 = new DirectionalLight(0xffffff, 2); - dirLight2.position.set(15, -40, -15); - dirLight2.shadow.camera.near = 3; - dirLight2.shadow.camera.far = 300; - dirLight2.shadow.camera.right = dist; - dirLight2.shadow.camera.left = -dist; - dirLight2.shadow.camera.top = dist; - dirLight2.shadow.camera.bottom = -dist; - - scene?.add(dirLight2); - - const material = new MeshPhongMaterial({ color: 0x444444 }); - material.shininess = 0; - material.specular = new Color(0x222222); - material.polygonOffset = true; - material.polygonOffsetFactor = 10; - const ground = new Mesh(new PlaneGeometry(740, 740, 1, 1), material); - ground.rotateX(-Math.PI / 2); - ground.receiveShadow = true; - current.ground = ground; - scene?.add(ground); - - createGui(); - } - }); - }; - - const disableGUI = () => { - const lilGui = document.getElementsByClassName('lil-gui')[0] as HTMLElement; - lilGui.style.pointerEvents = 'none'; - lilGui.style.opacity = '0.5'; - }; - - const enableGUI = () => { - const lilGui = document.getElementsByClassName('lil-gui')[0] as HTMLElement; - lilGui.style.pointerEvents = 'all'; - lilGui.style.opacity = '1'; - }; - - function showSpinner() { - const element = document.createElement('div'); - element.id = 'spinner'; - element.className = 'lds-ellipsis'; - element.innerHTML = ` -
-
-
- `; - - document.body.appendChild(element); - } - - function hideSpinner() { - const el = document.getElementById('spinner'); - if (el) { - el.remove(); - } - } - - const createGui = () => { - const gui = new GUI(); - current.gui = gui; - gui.$title.innerHTML = 'Pattern'; - - gui - .add(model, 'uHex', 1, 14, 1) - .name('Hexagons U') - .onFinishChange((value: number) => { - model.uHex = value; - updateShape(false); - }); - - gui - .add(model, 'vHex', 8, 36, 2) - .name('Hexagons V') - .onFinishChange((value: number) => { - model.vHex = value; - updateShape(false); - }); - - gui - .add(model, 'height', 15, 25, 1) - .name('Height') - .onFinishChange((value: number) => { - model.height = value; - updateShape(false); - }); - - gui - .add(model, 'ellipse2RotX', 0, 15, 0.1) - .name('Angle Guide') - .onFinishChange((value: number) => { - model.ellipse2RotX = value; - updateShape(false); - }); - - gui - .add(model, 'finalPrecision', 0.01, 1, 0.01) - .name('Final Precision') - .onFinishChange((value: number) => { - model.finalPrecision = value; - }); - - gui - .add(model, 'rotationEnabled') - .name('Rotation Enabled') - .onFinishChange((value: boolean) => { - model.rotationEnabled = value; - }); - - gui - .add(model, 'drawEdges') - .name('Draw Edges') - .onFinishChange((value: boolean) => { - model.drawEdges = value; - }); - - gui - .addColor(model, 'color1') - .name('Color 1') - .onChange((value: string) => { - current.group1?.children.forEach((group) => { - const children = group?.children[0].children as Mesh[]; - [...children].forEach((child) => { - const material = (child as Mesh).material as MeshPhongMaterial; - material.color.setHex(parseInt(value.replace('#', '0x'))); - }); + async function updateShape(finish: boolean) { + disableGUI(); + showSpinner(); + current.group1?.traverse((obj) => { + scene?.remove(obj); }); - }); - - gui - .addColor(model, 'color2') - .name('Color 2') - .onChange((value: string) => { - current.group2?.children.forEach((group) => { - const children = group?.children[0].children as Mesh[]; - [...children].forEach((child) => { - const material = (child as Mesh).material as MeshPhongMaterial; - material.color.setHex(parseInt(value.replace('#', '0x'))); - }); + current.group2?.traverse((obj) => { + scene?.remove(obj); }); - }); - - gui.add(model, 'update').name('Finalize'); - gui.add(model, 'downloadSTL').name('Download STL'); - gui.add(model, 'downloadStep').name('Download STEP'); - gui.add(model, 'downloadGLB').name('Download GLB'); - }; - - init(); + current.dimensions?.traverse((obj) => { + scene?.remove(obj); + }); + if (finish) { + finalShape = await createShapeLod2( + bitbybit, + scene, + model, + shapesToClean, + current + ); + } else { + finalShape = await createShapeLod1( + bitbybit, + scene, + model, + shapesToClean, + current + ); + } + hideSpinner(); + enableGUI(); + } } - -component(); diff --git a/examples/vite/threejs/hex-shell/src/models/current.ts b/examples/vite/threejs/hex-shell/src/models/current.ts index 8730c8e1..915eda6b 100644 --- a/examples/vite/threejs/hex-shell/src/models/current.ts +++ b/examples/vite/threejs/hex-shell/src/models/current.ts @@ -1,5 +1,5 @@ -import { DirectionalLight, Group, Mesh } from 'three'; -import { GUI } from 'lil-gui'; +import { DirectionalLight, Group, Mesh } from "three"; +import { GUI } from "lil-gui"; export type Current = { group1: Group | undefined; @@ -9,3 +9,12 @@ export type Current = { ground: Mesh | undefined; gui: GUI | undefined; }; + +export const current: Current = { + group1: undefined, + group2: undefined, + dimensions: undefined, + ground: undefined, + light1: undefined, + gui: undefined, +}; diff --git a/examples/vite/threejs/hex-shell/src/models/index.ts b/examples/vite/threejs/hex-shell/src/models/index.ts new file mode 100644 index 00000000..23e3b232 --- /dev/null +++ b/examples/vite/threejs/hex-shell/src/models/index.ts @@ -0,0 +1,3 @@ +export * from "./current"; +export * from "./kernel-options"; +export * from "./model"; diff --git a/examples/vite/threejs/hex-shell/src/models/kernel-options.ts b/examples/vite/threejs/hex-shell/src/models/kernel-options.ts new file mode 100644 index 00000000..a9a34b03 --- /dev/null +++ b/examples/vite/threejs/hex-shell/src/models/kernel-options.ts @@ -0,0 +1,5 @@ +export interface KernelOptions { + enableOCCT: boolean; + enableJSCAD: boolean; + enableManifold: boolean; +} diff --git a/examples/vite/threejs/hex-shell/src/models/model.ts b/examples/vite/threejs/hex-shell/src/models/model.ts index 5260fda4..863ca35f 100644 --- a/examples/vite/threejs/hex-shell/src/models/model.ts +++ b/examples/vite/threejs/hex-shell/src/models/model.ts @@ -1,24 +1,51 @@ +import type { BitByBitBase, Inputs } from "@bitbybit-dev/threejs"; +import type { Scene } from "three"; + export type Model = { - uHex: number; - vHex: number; - height: number; - ellipse1MinRad: number; - ellipse1MaxRad: number; - ellipse2MinRad: number; - ellipse2MaxRad: number; - ellipse2RotX: number; - ellipse2RotY: number; - ellipse3MinRad: number; - ellipse3MaxRad: number; - ellipse3YRot: number; - drawEdges: boolean; - drawFaces: boolean; - color1: string; - color2: string; - finalPrecision: number; - rotationEnabled: boolean; - downloadSTL?: () => void; - downloadStep?: () => void; - downloadGLB?: () => void; - update?: () => void; + uHex: number; + vHex: number; + height: number; + ellipse1MinRad: number; + ellipse1MaxRad: number; + ellipse2MinRad: number; + ellipse2MaxRad: number; + ellipse2RotX: number; + ellipse2RotY: number; + ellipse3MinRad: number; + ellipse3MaxRad: number; + ellipse3YRot: number; + drawEdges: boolean; + drawFaces: boolean; + color1: string; + color2: string; + finalPrecision: number; + rotationEnabled: boolean; + downloadSTL?: (scene: Scene) => void; + downloadStep?: ( + bitbybit: BitByBitBase, + finalShape: Inputs.OCCT.TopoDSShapePointer | undefined + ) => void; + downloadGLB?: (scene: Scene) => void; + update?: () => void; }; + +export const model = { + uHex: 3, + vHex: 12, + height: 15, + ellipse1MinRad: 15, + ellipse1MaxRad: 15, + ellipse2MinRad: 25, + ellipse2MaxRad: 30, + ellipse2RotX: 15, + ellipse2RotY: 15, + ellipse3MinRad: 45, + ellipse3MaxRad: 90, + ellipse3YRot: 45, + finalPrecision: 0.05, + drawEdges: false, + drawFaces: true, + rotationEnabled: false, + color1: "#b3ccff", + color2: "#ffffff", +} as Model; diff --git a/examples/vite/threejs/hex-shell/src/workers/jscad.worker.ts b/examples/vite/threejs/hex-shell/src/workers/jscad.worker.ts index 5ee5cda1..eeed36fd 100644 --- a/examples/vite/threejs/hex-shell/src/workers/jscad.worker.ts +++ b/examples/vite/threejs/hex-shell/src/workers/jscad.worker.ts @@ -1,12 +1,12 @@ import { initializationComplete, onMessageInput, -} from '@bitbybit-dev/jscad-worker'; +} from "@bitbybit-dev/jscad-worker"; -import('@bitbybit-dev/jscad/jscad-generated').then((s) => { +import("@bitbybit-dev/jscad/jscad-generated").then((s) => { initializationComplete(s.default()); }); -addEventListener('message', ({ data }) => { +addEventListener("message", ({ data }) => { onMessageInput(data, postMessage); }); diff --git a/examples/vite/threejs/hex-shell/src/workers/manifold.worker.ts b/examples/vite/threejs/hex-shell/src/workers/manifold.worker.ts index a7302543..889fad80 100644 --- a/examples/vite/threejs/hex-shell/src/workers/manifold.worker.ts +++ b/examples/vite/threejs/hex-shell/src/workers/manifold.worker.ts @@ -1,13 +1,13 @@ import { initializationComplete, onMessageInput, -} from '@bitbybit-dev/manifold-worker'; -import Module from 'manifold-3d'; +} from "@bitbybit-dev/manifold-worker"; +import Module from "manifold-3d"; const init = async () => { const wasm = await Module({ locateFile: () => { - return 'https://cdn.jsdelivr.net/gh/bitbybit-dev/bitbybit-assets@0.20.2/wasm/manifold.cc2ddd38.wasm'; + return "https://cdn.jsdelivr.net/gh/bitbybit-dev/bitbybit-assets@0.20.2/wasm/manifold.cc2ddd38.wasm"; }, }); wasm.setup(); @@ -16,6 +16,6 @@ const init = async () => { init(); -addEventListener('message', ({ data }) => { +addEventListener("message", ({ data }) => { onMessageInput(data, postMessage); }); diff --git a/examples/vite/threejs/hex-shell/src/workers/occt.worker.ts b/examples/vite/threejs/hex-shell/src/workers/occt.worker.ts index f613669d..492dfd44 100644 --- a/examples/vite/threejs/hex-shell/src/workers/occt.worker.ts +++ b/examples/vite/threejs/hex-shell/src/workers/occt.worker.ts @@ -1,14 +1,14 @@ -import initOpenCascade from '@bitbybit-dev/occt/bitbybit-dev-occt/cdn'; -import type { OpenCascadeInstance } from '@bitbybit-dev/occt/bitbybit-dev-occt/bitbybit-dev-occt.js'; +import initOpenCascade from "@bitbybit-dev/occt/bitbybit-dev-occt/cdn"; +import type { OpenCascadeInstance } from "@bitbybit-dev/occt/bitbybit-dev-occt/bitbybit-dev-occt.js"; import { initializationComplete, onMessageInput, -} from '@bitbybit-dev/occt-worker'; +} from "@bitbybit-dev/occt-worker"; initOpenCascade().then((occ: OpenCascadeInstance) => { initializationComplete(occ, undefined); }); -addEventListener('message', ({ data }) => { +addEventListener("message", ({ data }) => { onMessageInput(data, postMessage); });