Browse Source

Merge branch 'main' into v4

alvarosabu 1 year ago
parent
commit
5f20467415

+ 1 - 1
CONTRIBUTING.md

@@ -15,7 +15,7 @@ Thanks from the heart 💚 for taking the time to help out. This guide will help
 
 ## Setup
 
-All the packages in the ecosystem use [pnpm workspaces](https://pnpm.io/workspaces). PnPM is a package manager that is faster than npm and yarn. It also uses symlinks to avoid code duplication.
+All the packages in the ecosystem use [pnpm workspaces](https://pnpm.io/workspaces). Pnpm is a package manager that is faster than npm and yarn. It also uses symlinks to avoid code duplication.
 
 The `workspace` has the following structure:
 

+ 2 - 1
docs/.vitepress/config/de.ts

@@ -3,7 +3,7 @@ import type { DefaultTheme, LocaleSpecificConfig } from 'vitepress'
 export const deConfig: LocaleSpecificConfig<DefaultTheme.Config> = {
   themeConfig: {
     editLink: {
-      pattern: 'https://github.com/tresjs/tres/edit/main/packages/docs/:path',
+      pattern: 'https://github.com/tresjs/tres/edit/main/docs/:path',
       text: 'Änderungen an dieser Seite vorschlagen',
     },
     sidebar: [
@@ -77,6 +77,7 @@ export const deConfig: LocaleSpecificConfig<DefaultTheme.Config> = {
           { text: 'v-light-helper', link: '/de/directives/v-light-helper' },
           { text: 'v-always-look-at', link: '/de/directives/v-always-look-at' },
           { text: 'v-distance-to', link: '/de/directives/v-distance-to' },
+          { text: 'v-rotate', link: '/directives/v-rotate' },
         ],
       },
       {

+ 2 - 1
docs/.vitepress/config/en.ts

@@ -3,7 +3,7 @@ import type { DefaultTheme, LocaleSpecificConfig } from 'vitepress'
 export const enConfig: LocaleSpecificConfig<DefaultTheme.Config> = {
   themeConfig: {
     editLink: {
-      pattern: 'https://github.com/tresjs/tres/edit/main/packages/docs/:path',
+      pattern: 'https://github.com/tresjs/tres/edit/main/docs/:path',
       text: 'Suggest changes to this page',
     },
     sidebar: [
@@ -78,6 +78,7 @@ export const enConfig: LocaleSpecificConfig<DefaultTheme.Config> = {
           { text: 'v-light-helper', link: '/directives/v-light-helper' },
           { text: 'v-always-look-at', link: '/directives/v-always-look-at' },
           { text: 'v-distance-to', link: '/directives/v-distance-to' },
+          { text: 'v-rotate', link: '/directives/v-rotate' },
         ],
       },
       {

+ 2 - 1
docs/.vitepress/config/es.ts

@@ -3,7 +3,7 @@ import type { DefaultTheme, LocaleSpecificConfig } from 'vitepress'
 export const esConfig: LocaleSpecificConfig<DefaultTheme.Config> = {
   themeConfig: {
     editLink: {
-      pattern: 'https://github.com/tresjs/tres/edit/main/packages/docs/:path',
+      pattern: 'https://github.com/tresjs/tres/edit/main/docs/:path',
       text: 'Sugerir cambios a esta página',
     },
     sidebar: [
@@ -78,6 +78,7 @@ export const esConfig: LocaleSpecificConfig<DefaultTheme.Config> = {
           { text: 'v-light-helper', link: '/es/directives/v-light-helper' },
           { text: 'v-always-look-at', link: '/es/directives/v-always-look-at' },
           { text: 'v-distance-to', link: '/es/directives/v-distance-to' },
+          { text: 'v-rotate', link: '/directives/v-rotate' },
         ],
       },
       {

+ 2 - 1
docs/.vitepress/config/fr.ts

@@ -3,7 +3,7 @@ import type { DefaultTheme, LocaleSpecificConfig } from 'vitepress'
 export const frConfig: LocaleSpecificConfig<DefaultTheme.Config> = {
   themeConfig: {
     editLink: {
-      pattern: 'https://github.com/tresjs/tres/edit/main/packages/docs/:path',
+      pattern: 'https://github.com/tresjs/tres/edit/main/docs/:path',
       text: 'Suggérer un changement à cette page.',
     },
     sidebar: [
@@ -79,6 +79,7 @@ export const frConfig: LocaleSpecificConfig<DefaultTheme.Config> = {
           { text: 'v-light-helper', link: '/fr/directives/v-light-helper' },
           { text: 'v-always-look-at', link: '/fr/directives/v-always-look-at' },
           { text: 'v-distance-to', link: '/fr/directives/v-distance-to' },
+          { text: 'v-rotate', link: '/directives/v-rotate' },
         ],
       },
       {

+ 2 - 1
docs/.vitepress/config/nl.ts

@@ -3,7 +3,7 @@ import type { DefaultTheme, LocaleSpecificConfig } from 'vitepress'
 export const nlConfig: LocaleSpecificConfig<DefaultTheme.Config> = {
   themeConfig: {
     editLink: {
-      pattern: 'https://github.com/tresjs/tres/edit/main/packages/docs/:path',
+      pattern: 'https://github.com/tresjs/tres/edit/main/docs/:path',
       text: 'Stel wijzigingen op deze pagina voor',
     },
     sidebar: [
@@ -78,6 +78,7 @@ export const nlConfig: LocaleSpecificConfig<DefaultTheme.Config> = {
           { text: 'v-light-helper', link: '/nl/directives/v-light-helper' },
           { text: 'v-always-look-at', link: '/nl/directives/v-always-look-at' },
           { text: 'v-distance-to', link: '/nl/directives/v-distance-to' },
+          { text: 'v-rotate', link: '/directives/v-rotate' },
         ],
       },
       {

+ 2 - 1
docs/.vitepress/config/zh.ts

@@ -3,7 +3,7 @@ import type { DefaultTheme, LocaleSpecificConfig } from 'vitepress'
 export const zhConfig: LocaleSpecificConfig<DefaultTheme.Config> = {
   themeConfig: {
     editLink: {
-      pattern: 'https://github.com/tresjs/tres/edit/main/packages/docs/:path',
+      pattern: 'https://github.com/tresjs/tres/edit/main/docs/:path',
       text: '对本页内容给出建议',
     },
     sidebar: [
@@ -77,6 +77,7 @@ export const zhConfig: LocaleSpecificConfig<DefaultTheme.Config> = {
           { text: 'v-light-helper', link: '/zh/directives/v-light-helper' },
           { text: 'v-always-look-at', link: '/zh/directives/v-always-look-at' },
           { text: 'v-distance-to', link: '/zh/directives/v-distance-to' },
+          { text: 'v-rotate', link: '/directives/v-rotate' },
         ],
       },
       {

+ 91 - 6
docs/.vitepress/theme/components/HomeSponsors.vue

@@ -1,15 +1,13 @@
 <script setup lang="ts">
 import { VPHomeSponsors } from 'vitepress/theme'
-import { useSponsor } from '../composables/sponsor'
 
-const { data } = useSponsor()
+/* const { data } = useSponsor() */
 </script>
 
 <template>
   <VPHomeSponsors
-    v-if="data"
     message="TresJS is free and open source, made possible by wonderful sponsors."
-    :data="data"
+    :data="[]"
   />
   <div class="action">
     <a
@@ -18,9 +16,94 @@ const { data } = useSponsor()
       target="_blank"
       rel="noreferrer"
     >
-      Become a sponsor <i class="i-carbon-heart"></i>
+      Become a sponsor
     </a>
   </div>
+  <div class="action">
+    <p class="message">Consider supporting our friends</p>
+  </div>
+  <ul class="action flex flex-wrap w-full sm:w-2/3 md:1/3 mx-auto">
+    <li>
+      <a
+        class="sponsor"
+        href="https://github.com/sponsors/vitejs"
+        target="_blank"
+        rel="noreferrer"
+      >
+        Vite <i class="i-logos-vitejs ml-2"></i>
+      </a>
+    </li>
+    <li>
+      <a
+        class="sponsor"
+        href="https://github.com/sponsors/patak-dev"
+        target="_blank"
+        rel="noreferrer"
+      >
+        Patak <img class="w-5 h-5 rounded ml-2" src="https://avatars.githubusercontent.com/u/583075?v=4" alt="" />
+      </a>
+    </li>
+    <li>
+      <a
+        class="sponsor"
+        href="https://github.com/sponsors/antfu"
+        target="_blank"
+        rel="noreferrer"
+      >
+        Anthony Fu <img class="w-5 h-5 rounded ml-2" src="https://avatars.githubusercontent.com/u/11247099?v=4" alt="" />
+      </a>
+    </li>
+    <li>
+      <a
+        class="sponsor"
+        href="https://github.com/sponsors/posva"
+        target="_blank"
+        rel="noreferrer"
+      >
+        posva <img class="w-5 h-5 rounded ml-2" src="https://avatars.githubusercontent.com/u/664177?v=4" alt="" />
+      </a>
+    </li>
+    <li>
+      <a
+        class="sponsor"
+        href="https://github.com/sponsors/johnsoncodehk"
+        target="_blank"
+        rel="noreferrer"
+      >
+        Johnson Chu <img class="w-5 h-5 rounded ml-2" src="https://avatars.githubusercontent.com/u/16279759?v=4" alt="" />
+      </a>
+    </li>
+    <li>
+      <a
+        class="sponsor"
+        href="https://github.com/sponsors/CodyJasonBennett"
+        target="_blank"
+        rel="noreferrer"
+      >
+        Cody Bennet <img class="w-5 h-5 rounded ml-2" src="https://avatars.githubusercontent.com/u/23324155?v=4" alt="" />
+      </a>
+    </li>
+    <li>
+      <a
+        class="sponsor"
+        href="https://github.com/sponsors/nuxt"
+        target="_blank"
+        rel="noreferrer"
+      >
+        Daniel Roe <img class="w-5 h-5 rounded ml-2" src="https://avatars.githubusercontent.com/u/23360933?s=160&v=4" alt="" />
+      </a>
+    </li>
+    <li>
+      <a
+        class="sponsor"
+        href="https://github.com/sponsors/danielroe"
+        target="_blank"
+        rel="noreferrer"
+      >
+        Nuxt <img class="w-5 h-5 rounded ml-2" src="https://avatars.githubusercontent.com/u/28706372?v=4" alt="" />
+      </a>
+    </li>
+  </ul>
 </template>
 
 <style scoped>
@@ -33,7 +116,9 @@ const { data } = useSponsor()
 
 .sponsor {
   /* .VPButton */
-  display: inline-block;
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
   border: 1px solid transparent;
   text-align: center;
   font-weight: 600;

+ 4 - 0
docs/.vitepress/theme/custom.css

@@ -58,3 +58,7 @@
   color: var(--vp-button-alt-text);
   background-color: var(--vp-button-alt-bg);
 }
+
+.VPHomeSponsors {
+  margin-bottom: 0px !important;
+}

+ 4 - 4
docs/directives/v-always-look-at.md

@@ -6,8 +6,8 @@ With the new directive v-always-look-at provided by **TresJS**, you can add easi
 
 ```vue{3,9}
 <script setup lang="ts">
-import { TresCanvas } from '@tresjs/core'
-import { Box, vAlwaysLookAt } from '@tresjs/cientos'
+import { TresCanvas, vAlwaysLookAt } from '@tresjs/core'
+import { Box } from '@tresjs/cientos'
 </script>
 <template>
     <TresCanvas >
@@ -33,8 +33,8 @@ Another advantage is that you can look at an instance in movement, for example w
 ```vue{4,6,20,23}
 <script setup lang="ts">
 import { shallowRef } from 'vue'
-import { TresCanvas, useRenderLoop } from '@tresjs/core'
-import { Box, vAlwaysLookAt } from '@tresjs/cientos'
+import { TresCanvas, useRenderLoop, vAlwaysLookAt } from '@tresjs/core'
+import { Box } from '@tresjs/cientos'
 
 const sphereRef = shallowRef()
 

+ 2 - 1
docs/directives/v-distance-to.md

@@ -8,7 +8,8 @@ In addition, an arrow will be created to indicate which objects you're measuring
 
 ```vue{2,8,13}
 <script setup lang="ts">
-import { OrbitControls, Sphere, vLog } from '@tresjs/cientos'
+import { vDistanceTo } from '@tresjs/core'
+import { OrbitControls, Sphere } from '@tresjs/cientos'
 </script>
 <template>
   <TresCanvas v-bind="gl">

+ 2 - 1
docs/directives/v-light-helper.md

@@ -12,7 +12,8 @@ The following lights are supported:
 
 ```vue{2,8,11,14,17}
 <script setup lang="ts">
-import { OrbitControls, Sphere, vLightHelper } from '@tresjs/cientos'
+import { vLightHelper } from '@tresjs/core'
+import { OrbitControls, Sphere,  } from '@tresjs/cientos'
 </script>
 <template>
   <TresCanvas >

+ 2 - 1
docs/directives/v-log.md

@@ -35,7 +35,8 @@ With the new directive v-log provided by **TresJS**, you can do this by just add
 
 ```vue{2,10,12}
 <script setup lang="ts">
-import { OrbitControls, Sphere, vLog } from '@tresjs/cientos'
+import { vLog } from '@tresjs/core'
+import { OrbitControls, Sphere } from '@tresjs/cientos'
 </script>
 <template>
     <TresCanvas >

+ 80 - 0
docs/directives/v-rotate.md

@@ -0,0 +1,80 @@
+# v-rotate
+
+## Problem
+
+When you want to simply add rotation to your mesh, you have to use the template reference, [useRenderLoop](/api/composables#userenderloop) and then assign the axis and the speed, but before check if you mesh is already available:
+
+```vue
+<script setup lang="ts">
+import { shallowRef, watch } from 'vue'
+import { useRenderLoop } from '@tresjs/core'
+
+const boxRef = shallowRef()
+
+const { onLoop } = useRenderLoop()
+
+onLoop(({ elapsed }) => {
+  if (boxRef.value) {
+    boxRef.value.rotation.x = elapsed
+  }
+})
+</script>
+
+<template>
+  <TresCanvas>
+    <TresPerspectiveCamera :position="[0, 2, 5]" />
+    <TresMesh
+      ref="boxRef"
+      :scale="0.5"
+    >
+      <TresBoxGeometry />
+      <TresMesh>
+        <OrbitControls />
+      </TresMesh>
+    </TresMesh>
+  </TresCanvas>
+</template>
+```
+
+And is A LOT of code just for a simple rotation right? Normally we need something fast to see if something is working
+
+## Usage
+
+With the new directive v-rotate provided by **TresJS**, you can do this by just adding `v-rotate` to the instance.
+
+```vue{2,8}
+<script setup lang="ts">
+import { vRotate } from '@tresjs/core'
+</script>
+<template>
+    <TresCanvas >
+    <TresPerspectiveCamera :position="[0, 2, 5]" />
+    <TresMesh
+      v-rotate // 😍
+    >
+      <TresBoxGeometry />
+    </TresMesh>
+  </TresCanvas>
+</template>
+```
+By default `v-rotate` uses [Quaternions](https://threejs.org/docs/index.html?q=quater#api/en/math/Quaternion) so you don't have to worry by [Gimbal Lock](https://en.wikipedia.org/wiki/Gimbal_lock), or check if you mesh is available in the first frames.
+
+## Modifiers
+
+You can control the axis and the rotation speed by adding modifiers
+
+```vue{2,8}
+<script setup lang="ts">
+import { vRotate } from '@tresjs/core'
+</script>
+<template>
+    <TresCanvas >
+    <TresPerspectiveCamera :position="[0, 2, 5]" />
+    <TresMesh
+      v-rotate:x.y="0.1" // the axis will be x and y with a speed of 0.1
+    >
+      <TresBoxGeometry />
+    </TresMesh>
+  </TresCanvas>
+</template>
+```

+ 3 - 1
docs/package.json

@@ -12,7 +12,9 @@
     "@tresjs/core": "workspace:^"
   },
   "devDependencies": {
-    "unocss": "^0.58.3",
+    "@iconify-json/logos": "^1.1.42",
+    "@iconify-json/mdi": "^1.1.66",
+    "unocss": "^0.58.0",
     "vite-svg-loader": "^5.1.0"
   }
 }

+ 15 - 1
docs/vite.config.ts

@@ -2,11 +2,25 @@ import { defineConfig } from 'vite'
 import Unocss from 'unocss/vite'
 import svgLoader from 'vite-svg-loader'
 import Components from 'unplugin-vue-components/vite'
+import { presetIcons, presetUno } from 'unocss'
 
 export default defineConfig({
   plugins: [
     svgLoader(),
-    Unocss(),
+    Unocss({
+      presets: [
+        presetUno(),
+        presetIcons({
+          scale: 1.2,
+          warn: true,
+          extraProperties: {
+            'display': 'inline-block',
+            'vertical-align': 'middle',
+            // ...
+          },
+        }),
+      ],
+    }),
     Components({
       // allow auto load markdown components under `.vitepress/theme/components`
       dirs: ['.vitepress/theme/components'],

+ 13 - 3
playground/src/pages/basic/Lights.vue

@@ -1,6 +1,6 @@
 <script setup lang="ts">
 import type { TresObject } from '@tresjs/core'
-import { TresCanvas, vAlwaysLookAt, vDistanceTo, vLightHelper, vLog } from '@tresjs/core'
+import { TresCanvas, vAlwaysLookAt, vDistanceTo, vLightHelper, vLog, vRotate } from '@tresjs/core'
 import { BasicShadowMap, NoToneMapping, SRGBColorSpace } from 'three'
 
 import { OrbitControls } from '@tresjs/cientos'
@@ -22,7 +22,11 @@ const planeRef: Ref<TresObject | null> = ref(null)
 
     v-bind="gl"
   >
-    <TresPerspectiveCamera :position="[3, 3, 3]" />
+    <TresPerspectiveCamera
+      v-distance-to="planeRef"
+      v-rotate
+      :position="[3, 3, 3]"
+    />
     <OrbitControls />
 
     <TresDirectionalLight
@@ -43,7 +47,13 @@ const planeRef: Ref<TresObject | null> = ref(null)
       <TresMeshToonMaterial />
     </TresMesh>
     <TresMesh
-      v-distance-to="planeRef"
+      v-rotate.x="0.005"
+      :position="[-2, 2, 0]"
+    >
+      <TresBoxGeometry :args="[1, 1, 1]" />
+      <TresMeshToonMaterial color="red" />
+    </TresMesh>
+    <TresMesh
       :position="[2, 4, 0]"
       cast-shadow
     >

+ 207 - 176
pnpm-lock.yaml

@@ -16,7 +16,7 @@ importers:
         version: 6.6.1
       '@vueuse/core':
         specifier: ^10.9.0
-        version: 10.9.0(vue@3.4.22)
+        version: 10.9.0(vue@3.4.23)
     devDependencies:
       '@release-it/conventional-changelog':
         specifier: ^8.0.1
@@ -26,10 +26,10 @@ importers:
         version: 1.9.0
       '@tresjs/cientos':
         specifier: 3.8.0
-        version: 3.8.0(@tresjs/core@3.5.1)(three@0.163.0)(tweakpane@4.0.3)(vue@3.4.22)
+        version: 3.8.0(@tresjs/core@3.5.1)(three@0.163.0)(tweakpane@4.0.3)(vue@3.4.23)
       '@tresjs/eslint-config':
         specifier: ^1.0.0
-        version: 1.0.0(@vue/compiler-sfc@3.4.22)(eslint@8.57.0)(typescript@5.4.5)(vitest@1.5.0)
+        version: 1.0.0(@vue/compiler-sfc@3.4.23)(eslint@8.57.0)(typescript@5.4.5)(vitest@1.5.0)
       '@types/three':
         specifier: ^0.163.0
         version: 0.163.0
@@ -41,7 +41,7 @@ importers:
         version: 7.7.0(eslint@8.57.0)(typescript@5.4.5)
       '@vitejs/plugin-vue':
         specifier: ^5.0.4
-        version: 5.0.4(vite@5.2.9)(vue@3.4.22)
+        version: 5.0.4(vite@5.2.9)(vue@3.4.23)
       '@vitest/coverage-c8':
         specifier: ^0.33.0
         version: 0.33.0(vitest@1.5.0)
@@ -101,7 +101,7 @@ importers:
         version: 1.10.1
       unplugin-vue-components:
         specifier: ^0.26.0
-        version: 0.26.0(vue@3.4.22)
+        version: 0.26.0(vue@3.4.23)
       vite:
         specifier: ^5.2.9
         version: 5.2.9
@@ -119,7 +119,7 @@ importers:
         version: 1.0.21
       vite-svg-loader:
         specifier: ^5.1.0
-        version: 5.1.0(vue@3.4.22)
+        version: 5.1.0(vue@3.4.23)
       vitepress:
         specifier: 1.1.0
         version: 1.1.0(@algolia/client-search@4.23.3)(postcss@8.4.38)(search-insights@2.13.0)(typescript@5.4.5)
@@ -128,10 +128,10 @@ importers:
         version: 1.5.0(@vitest/ui@1.5.0)(jsdom@24.0.0)
       vue:
         specifier: ^3.4.22
-        version: 3.4.22(typescript@5.4.5)
+        version: 3.4.23(typescript@5.4.5)
       vue-demi:
         specifier: ^0.14.7
-        version: 0.14.7(vue@3.4.22)
+        version: 0.14.7(vue@3.4.23)
 
   docs:
     dependencies:
@@ -139,28 +139,34 @@ importers:
         specifier: workspace:^
         version: link:..
     devDependencies:
+      '@iconify-json/logos':
+        specifier: ^1.1.42
+        version: 1.1.42
+      '@iconify-json/mdi':
+        specifier: ^1.1.66
+        version: 1.1.66
       unocss:
-        specifier: ^0.58.3
+        specifier: ^0.58.0
         version: 0.58.7(postcss@8.4.38)(vite@5.2.9)
       vite-svg-loader:
         specifier: ^5.1.0
-        version: 5.1.0(vue@3.4.22)
+        version: 5.1.0(vue@3.4.23)
 
   playground:
     dependencies:
       '@tresjs/cientos':
         specifier: 3.6.0
-        version: 3.6.0(@tresjs/core@)(three@0.163.0)(tweakpane@4.0.3)(vue@3.4.22)
+        version: 3.6.0(@tresjs/core@)(three@0.163.0)(tweakpane@4.0.3)(vue@3.4.23)
       '@tresjs/core':
         specifier: workspace:^
         version: link:..
       vue-router:
         specifier: ^4.2.5
-        version: 4.3.0(vue@3.4.22)
+        version: 4.3.1(vue@3.4.23)
     devDependencies:
       '@tresjs/leches':
         specifier: 0.15.0-next.3
-        version: 0.15.0-next.3(three@0.163.0)(vite@5.2.9)(vue@3.4.22)
+        version: 0.15.0-next.3(three@0.163.0)(vite@5.2.9)(vue@3.4.23)
       '@tweakpane/plugin-essentials':
         specifier: ^0.2.0
         version: 0.2.1(tweakpane@4.0.3)
@@ -348,7 +354,7 @@ packages:
       '@jridgewell/trace-mapping': 0.3.25
     dev: true
 
-  /@antfu/eslint-config@2.13.0(@vue/compiler-sfc@3.4.22)(eslint-plugin-format@0.1.0)(eslint@8.57.0)(typescript@5.4.5)(vitest@1.5.0):
+  /@antfu/eslint-config@2.13.0(@vue/compiler-sfc@3.4.23)(eslint-plugin-format@0.1.0)(eslint@8.57.0)(typescript@5.4.5)(vitest@1.5.0):
     resolution: {integrity: sha512-yI3X5ispR8jWnUz9gtPoEF5Wug/a+7rF/bQ34nVWnAB86LZUhOOR8jbR+ihD+OGkU/BTcfzVEKCK78SgqoS5xA==}
     hasBin: true
     peerDependencies:
@@ -416,7 +422,7 @@ packages:
       eslint-plugin-vitest: 0.4.1(@typescript-eslint/eslint-plugin@7.7.0)(eslint@8.57.0)(typescript@5.4.5)(vitest@1.5.0)
       eslint-plugin-vue: 9.25.0(eslint@8.57.0)
       eslint-plugin-yml: 1.14.0(eslint@8.57.0)
-      eslint-processor-vue-blocks: 0.1.1(@vue/compiler-sfc@3.4.22)(eslint@8.57.0)
+      eslint-processor-vue-blocks: 0.1.1(@vue/compiler-sfc@3.4.23)(eslint@8.57.0)
       globals: 15.0.0
       jsonc-eslint-parser: 2.4.0
       local-pkg: 0.5.0
@@ -474,7 +480,7 @@ packages:
       '@babel/helper-compilation-targets': 7.23.6
       '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.3)
       '@babel/helpers': 7.24.1
-      '@babel/parser': 7.24.1
+      '@babel/parser': 7.24.4
       '@babel/template': 7.24.0
       '@babel/traverse': 7.24.1
       '@babel/types': 7.24.0
@@ -851,6 +857,18 @@ packages:
       '@babel/helper-plugin-utils': 7.24.0
     dev: true
 
+  /@babel/plugin-transform-modules-commonjs@7.24.1(@babel/core@7.24.3):
+    resolution: {integrity: sha512-szog8fFTUxBfw0b98gEWPaEqF42ZUD/T3bkynW/wtgx2p/XCP55WEsb+VosKceRSd6njipdZvNogqdtI4Q0chw==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.24.3
+      '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.3)
+      '@babel/helper-plugin-utils': 7.24.0
+      '@babel/helper-simple-access': 7.22.5
+    dev: true
+
   /@babel/plugin-transform-modules-commonjs@7.24.1(@babel/core@7.24.4):
     resolution: {integrity: sha512-szog8fFTUxBfw0b98gEWPaEqF42ZUD/T3bkynW/wtgx2p/XCP55WEsb+VosKceRSd6njipdZvNogqdtI4Q0chw==}
     engines: {node: '>=6.9.0'}
@@ -889,6 +907,20 @@ packages:
       '@babel/plugin-syntax-typescript': 7.24.1(@babel/core@7.24.4)
     dev: true
 
+  /@babel/preset-typescript@7.24.1(@babel/core@7.24.3):
+    resolution: {integrity: sha512-1DBaMmRDpuYQBPWD8Pf/WEwCrtgRHxsZnP4mIy9G/X+hFfbI47Q2G4t1Paakld84+qsk2fSsUPMKg71jkoOOaQ==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.24.3
+      '@babel/helper-plugin-utils': 7.24.0
+      '@babel/helper-validator-option': 7.23.5
+      '@babel/plugin-syntax-jsx': 7.24.1(@babel/core@7.24.3)
+      '@babel/plugin-transform-modules-commonjs': 7.24.1(@babel/core@7.24.3)
+      '@babel/plugin-transform-typescript': 7.24.1(@babel/core@7.24.3)
+    dev: true
+
   /@babel/preset-typescript@7.24.1(@babel/core@7.24.4):
     resolution: {integrity: sha512-1DBaMmRDpuYQBPWD8Pf/WEwCrtgRHxsZnP4mIy9G/X+hFfbI47Q2G4t1Paakld84+qsk2fSsUPMKg71jkoOOaQ==}
     engines: {node: '>=6.9.0'}
@@ -917,12 +949,12 @@ packages:
     engines: {node: '>=6.9.0'}
     dependencies:
       '@babel/code-frame': 7.24.2
-      '@babel/generator': 7.24.4
+      '@babel/generator': 7.24.1
       '@babel/helper-environment-visitor': 7.22.20
       '@babel/helper-function-name': 7.23.0
       '@babel/helper-hoist-variables': 7.22.5
       '@babel/helper-split-export-declaration': 7.22.6
-      '@babel/parser': 7.24.4
+      '@babel/parser': 7.24.1
       '@babel/types': 7.24.0
       debug: 4.3.4
       globals: 11.12.0
@@ -1508,10 +1540,36 @@ packages:
     resolution: {integrity: sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==}
     dev: true
 
+  /@iconify-json/logos@1.1.42:
+    resolution: {integrity: sha512-/f+frtPm3m3Z30oy8Pk+QqRDkbmAiIaWGPl5CmsCXm15MVfvw9a/V/gD7WzdyuSGAZcFuQaqbHXj92y/n+2ifg==}
+    dependencies:
+      '@iconify/types': 2.0.0
+    dev: true
+
+  /@iconify-json/mdi@1.1.66:
+    resolution: {integrity: sha512-7KPF2RVUUWav/hXCM8Ti/smqu3cmgePJpiX9CSkldiL+80+eBRBeKlc4vPOc9jhAItlqIU1vKsbKoPP0JIfgbg==}
+    dependencies:
+      '@iconify/types': 2.0.0
+    dev: true
+
   /@iconify/types@2.0.0:
     resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==}
     dev: true
 
+  /@iconify/utils@2.1.22:
+    resolution: {integrity: sha512-6UHVzTVXmvO8uS6xFF+L/QTSpTzA/JZxtgU+KYGFyDYMEObZ1bu/b5l+zNJjHy+0leWjHI+C0pXlzGvv3oXZMA==}
+    dependencies:
+      '@antfu/install-pkg': 0.1.1
+      '@antfu/utils': 0.7.7
+      '@iconify/types': 2.0.0
+      debug: 4.3.4
+      kolorist: 1.8.0
+      local-pkg: 0.5.0
+      mlly: 1.6.1
+    transitivePeerDependencies:
+      - supports-color
+    dev: true
+
   /@iconify/utils@2.1.23:
     resolution: {integrity: sha512-YGNbHKM5tyDvdWZ92y2mIkrfvm5Fvhe6WJSkWu7vvOFhMtYDP0casZpoRz0XEHZCrYsR4stdGT3cZ52yp5qZdQ==}
     dependencies:
@@ -2117,7 +2175,7 @@ packages:
     resolution: {integrity: sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==}
     dev: true
 
-  /@tresjs/cientos@3.6.0(@tresjs/core@)(three@0.163.0)(tweakpane@4.0.3)(vue@3.4.22):
+  /@tresjs/cientos@3.6.0(@tresjs/core@)(three@0.163.0)(tweakpane@4.0.3)(vue@3.4.23):
     resolution: {integrity: sha512-VM6LamAFlcKufbrtbYN71ncuAw2JPVfKUC6Ey9+scq05qvHdQM8fU0WoppNZEtmIL7m2aUqroOZRnr9LXyZPCg==}
     peerDependencies:
       '@tresjs/core': '>=3.2'
@@ -2126,7 +2184,7 @@ packages:
       vue: '>=3.3'
     dependencies:
       '@tresjs/core': 'link:'
-      '@vueuse/core': 10.9.0(vue@3.4.22)
+      '@vueuse/core': 10.9.0(vue@3.4.23)
       camera-controls: 2.8.3(three@0.163.0)
       stats-gl: 1.0.7
       stats.js: 0.17.0
@@ -2134,14 +2192,14 @@ packages:
       three-custom-shader-material: 5.4.0(three@0.163.0)
       three-stdlib: 2.29.6(three@0.163.0)
       tweakpane: 4.0.3
-      vue: 3.4.22(typescript@5.4.5)
+      vue: 3.4.23(typescript@5.4.5)
     transitivePeerDependencies:
       - '@react-three/fiber'
       - '@vue/composition-api'
       - react
     dev: false
 
-  /@tresjs/cientos@3.8.0(@tresjs/core@3.5.1)(three@0.163.0)(tweakpane@4.0.3)(vue@3.4.22):
+  /@tresjs/cientos@3.8.0(@tresjs/core@3.5.1)(three@0.163.0)(tweakpane@4.0.3)(vue@3.4.23):
     resolution: {integrity: sha512-m3lyrBHrHkwkDG28B/vQQUeQ9FlG5C50bkULYEoQXrpIAM8toC11DpxY6VMMvbFc4qhZA5QdTZIlznJ8ZDopFQ==}
     peerDependencies:
       '@tresjs/core': '>=3.2'
@@ -2149,8 +2207,8 @@ packages:
       tweakpane: '>=3.0.0'
       vue: '>=3.3'
     dependencies:
-      '@tresjs/core': 3.5.1(three@0.163.0)(vue@3.4.22)
-      '@vueuse/core': 10.9.0(vue@3.4.22)
+      '@tresjs/core': 3.5.1(three@0.163.0)(vue@3.4.23)
+      '@vueuse/core': 10.9.0(vue@3.4.23)
       camera-controls: 2.8.3(three@0.163.0)
       stats-gl: 2.2.8
       stats.js: 0.17.0
@@ -2158,33 +2216,33 @@ packages:
       three-custom-shader-material: 5.4.0(three@0.163.0)
       three-stdlib: 2.29.6(three@0.163.0)
       tweakpane: 4.0.3
-      vue: 3.4.22(typescript@5.4.5)
+      vue: 3.4.23(typescript@5.4.5)
     transitivePeerDependencies:
       - '@react-three/fiber'
       - '@vue/composition-api'
       - react
     dev: true
 
-  /@tresjs/core@3.5.1(three@0.163.0)(vue@3.4.22):
+  /@tresjs/core@3.5.1(three@0.163.0)(vue@3.4.23):
     resolution: {integrity: sha512-j7fHT3X8NamQk+n5A20r/UUkInHWQOJr5dzzcuOCdD6s3FFc3WMYtbRq+cJN8FR8mS0vpSK6h9s82com8cmRNA==}
     peerDependencies:
       three: '>=0.133'
       vue: '>=3.3'
     dependencies:
       '@alvarosabu/utils': 3.2.0
-      '@vueuse/core': 10.9.0(vue@3.4.22)
+      '@vueuse/core': 10.9.0(vue@3.4.23)
       three: 0.163.0
-      vue: 3.4.22(typescript@5.4.5)
+      vue: 3.4.23(typescript@5.4.5)
     transitivePeerDependencies:
       - '@vue/composition-api'
     dev: true
 
-  /@tresjs/eslint-config@1.0.0(@vue/compiler-sfc@3.4.22)(eslint@8.57.0)(typescript@5.4.5)(vitest@1.5.0):
+  /@tresjs/eslint-config@1.0.0(@vue/compiler-sfc@3.4.23)(eslint@8.57.0)(typescript@5.4.5)(vitest@1.5.0):
     resolution: {integrity: sha512-m28JMAHfJ/jSESh5o38EdPfD27HD+ptRiUSh6lgF6CY8mQ5QreFlTzUcYsaBqvoCC1PnKzUyGBBomscXj5X5cw==}
     peerDependencies:
       eslint: 8.x
     dependencies:
-      '@antfu/eslint-config': 2.13.0(@vue/compiler-sfc@3.4.22)(eslint-plugin-format@0.1.0)(eslint@8.57.0)(typescript@5.4.5)(vitest@1.5.0)
+      '@antfu/eslint-config': 2.13.0(@vue/compiler-sfc@3.4.23)(eslint-plugin-format@0.1.0)(eslint@8.57.0)(typescript@5.4.5)(vitest@1.5.0)
       eslint: 8.57.0
       eslint-plugin-format: 0.1.0(eslint@8.57.0)
     transitivePeerDependencies:
@@ -2206,19 +2264,19 @@ packages:
       - vitest
     dev: true
 
-  /@tresjs/leches@0.15.0-next.3(three@0.163.0)(vite@5.2.9)(vue@3.4.22):
+  /@tresjs/leches@0.15.0-next.3(three@0.163.0)(vite@5.2.9)(vue@3.4.23):
     resolution: {integrity: sha512-kI8DovuzZ/mnSY3ifEiKJ1fd3aBoM5hYSfX0uwlJ6KWblVafrhds1J8j5aoFq6Kx0pjDVsY72fL8itAfm0ZrzQ==}
     peerDependencies:
       three: '>=0.133'
       vue: '>=3.3.4'
     dependencies:
-      '@tresjs/core': 3.5.1(three@0.163.0)(vue@3.4.22)
+      '@tresjs/core': 3.5.1(three@0.163.0)(vue@3.4.23)
       '@types/three': 0.158.3
       '@unocss/core': 0.57.7
-      '@vueuse/components': 10.9.0(vue@3.4.22)
+      '@vueuse/components': 10.9.0(vue@3.4.23)
       three: 0.163.0
       vite-plugin-css-injected-by-js: 3.5.0(vite@5.2.9)
-      vue: 3.4.22(typescript@5.4.5)
+      vue: 3.4.23(typescript@5.4.5)
     transitivePeerDependencies:
       - '@vue/composition-api'
       - vite
@@ -2604,7 +2662,7 @@ packages:
       colorette: 2.0.20
       consola: 3.2.3
       fast-glob: 3.3.2
-      magic-string: 0.30.9
+      magic-string: 0.30.10
       pathe: 1.1.2
       perfect-debounce: 1.0.0
     transitivePeerDependencies:
@@ -2626,7 +2684,7 @@ packages:
       colorette: 2.0.20
       consola: 3.2.3
       fast-glob: 3.3.2
-      magic-string: 0.30.9
+      magic-string: 0.30.10
       pathe: 1.1.2
       perfect-debounce: 1.0.0
     transitivePeerDependencies:
@@ -2638,7 +2696,7 @@ packages:
     engines: {node: '>=14'}
     dependencies:
       '@unocss/core': 0.58.7
-      unconfig: 0.3.13
+      unconfig: 0.3.11
     dev: true
 
   /@unocss/config@0.59.3:
@@ -2702,7 +2760,7 @@ packages:
       '@unocss/rule-utils': 0.58.7
       css-tree: 2.3.1
       fast-glob: 3.3.2
-      magic-string: 0.30.9
+      magic-string: 0.30.10
       postcss: 8.4.38
     dev: true
 
@@ -2717,7 +2775,7 @@ packages:
       '@unocss/rule-utils': 0.59.3
       css-tree: 2.3.1
       fast-glob: 3.3.2
-      magic-string: 0.30.9
+      magic-string: 0.30.10
       postcss: 8.4.38
     dev: true
 
@@ -2736,7 +2794,7 @@ packages:
   /@unocss/preset-icons@0.58.7:
     resolution: {integrity: sha512-GeFaWiWGDktRs9TKqT4gb78Cjo7qlatOTijfJ1Zoyd3QMfbg7mRJPZGgHnLtpwYju+QKxG618fwlGvzARKhNfg==}
     dependencies:
-      '@iconify/utils': 2.1.23
+      '@iconify/utils': 2.1.22
       '@unocss/core': 0.58.7
       ofetch: 1.3.4
     transitivePeerDependencies:
@@ -2856,7 +2914,7 @@ packages:
     engines: {node: '>=14'}
     dependencies:
       '@unocss/core': 0.58.7
-      magic-string: 0.30.9
+      magic-string: 0.30.10
     dev: true
 
   /@unocss/rule-utils@0.59.3:
@@ -2864,7 +2922,7 @@ packages:
     engines: {node: '>=14'}
     dependencies:
       '@unocss/core': 0.59.3
-      magic-string: 0.30.9
+      magic-string: 0.30.10
     dev: true
 
   /@unocss/scope@0.58.7:
@@ -2878,9 +2936,9 @@ packages:
   /@unocss/transformer-attributify-jsx-babel@0.58.7:
     resolution: {integrity: sha512-IxEPQG7Kn+NgYEogOSKfqfGMQR7WU8X2DctaGBoQlizMiDr+q9DXM1dgGU0bXMxnSpRF8DYFHvgHefRnNUUVPg==}
     dependencies:
-      '@babel/core': 7.24.4
-      '@babel/plugin-syntax-jsx': 7.24.1(@babel/core@7.24.4)
-      '@babel/preset-typescript': 7.24.1(@babel/core@7.24.4)
+      '@babel/core': 7.24.3
+      '@babel/plugin-syntax-jsx': 7.24.1(@babel/core@7.24.3)
+      '@babel/preset-typescript': 7.24.1(@babel/core@7.24.3)
       '@unocss/core': 0.58.7
     transitivePeerDependencies:
       - supports-color
@@ -2963,7 +3021,7 @@ packages:
       '@unocss/transformer-directives': 0.58.7
       chokidar: 3.6.0
       fast-glob: 3.3.2
-      magic-string: 0.30.9
+      magic-string: 0.30.10
       vite: 5.2.9
     transitivePeerDependencies:
       - rollup
@@ -2983,7 +3041,7 @@ packages:
       '@unocss/transformer-directives': 0.59.3
       chokidar: 3.6.0
       fast-glob: 3.3.2
-      magic-string: 0.30.9
+      magic-string: 0.30.10
       vite: 5.2.9
     transitivePeerDependencies:
       - rollup
@@ -3002,7 +3060,7 @@ packages:
       vite-hot-client: 0.2.3(vite@5.2.9)
     dev: true
 
-  /@vitejs/plugin-vue@5.0.4(vite@5.2.9)(vue@3.4.22):
+  /@vitejs/plugin-vue@5.0.4(vite@5.2.9)(vue@3.4.23):
     resolution: {integrity: sha512-WS3hevEszI6CEVEx28F8RjTX97k3KsrcY6kvTg7+Whm5y3oYvcqzVeGCU3hxSAn4uY2CLCkeokkGKpoctccilQ==}
     engines: {node: ^18.0.0 || >=20.0.0}
     peerDependencies:
@@ -3010,7 +3068,7 @@ packages:
       vue: ^3.2.25
     dependencies:
       vite: 5.2.9
-      vue: 3.4.22(typescript@5.4.5)
+      vue: 3.4.23(typescript@5.4.5)
     dev: true
 
   /@vitest/coverage-c8@0.33.0(vitest@1.5.0):
@@ -3156,95 +3214,57 @@ packages:
       '@babel/core': 7.24.3
       '@babel/helper-module-imports': 7.22.15
       '@babel/helper-plugin-utils': 7.24.0
-      '@babel/parser': 7.24.1
-      '@vue/compiler-sfc': 3.4.21
-    dev: true
-
-  /@vue/compiler-core@3.4.21:
-    resolution: {integrity: sha512-MjXawxZf2SbZszLPYxaFCjxfibYrzr3eYbKxwpLR9EQN+oaziSu3qKVbwBERj1IFIB8OLUewxB5m/BFzi613og==}
-    dependencies:
-      '@babel/parser': 7.24.1
-      '@vue/shared': 3.4.21
-      entities: 4.5.0
-      estree-walker: 2.0.2
-      source-map-js: 1.2.0
+      '@babel/parser': 7.24.4
+      '@vue/compiler-sfc': 3.4.23
     dev: true
 
-  /@vue/compiler-core@3.4.22:
-    resolution: {integrity: sha512-FBDRCBE/rFPA8OfTUrARx2c49N7zoImlGT7hsFikv0pZxQlFhffQwewpEXaLynZW0/DspVXmNA+QQ9dXINpWmg==}
+  /@vue/compiler-core@3.4.23:
+    resolution: {integrity: sha512-HAFmuVEwNqNdmk+w4VCQ2pkLk1Vw4XYiiyxEp3z/xvl14aLTUBw2OfVH3vBcx+FtGsynQLkkhK410Nah1N2yyQ==}
     dependencies:
       '@babel/parser': 7.24.4
-      '@vue/shared': 3.4.22
+      '@vue/shared': 3.4.23
       entities: 4.5.0
       estree-walker: 2.0.2
       source-map-js: 1.2.0
 
-  /@vue/compiler-dom@3.4.21:
-    resolution: {integrity: sha512-IZC6FKowtT1sl0CR5DpXSiEB5ayw75oT2bma1BEhV7RRR1+cfwLrxc2Z8Zq/RGFzJ8w5r9QtCOvTjQgdn0IKmA==}
-    dependencies:
-      '@vue/compiler-core': 3.4.21
-      '@vue/shared': 3.4.21
-    dev: true
-
-  /@vue/compiler-dom@3.4.22:
-    resolution: {integrity: sha512-YkAS+jZc6Ip360kT3lZbMQZteiYBbHDSVKr94Jdd8Zjr7VjSkkXKAFFR/FW+2tNtBYXOps6xrWlOquy3GeYB0w==}
+  /@vue/compiler-dom@3.4.23:
+    resolution: {integrity: sha512-t0b9WSTnCRrzsBGrDd1LNR5HGzYTr7LX3z6nNBG+KGvZLqrT0mY6NsMzOqlVMBKKXKVuusbbB5aOOFgTY+senw==}
     dependencies:
-      '@vue/compiler-core': 3.4.22
-      '@vue/shared': 3.4.22
+      '@vue/compiler-core': 3.4.23
+      '@vue/shared': 3.4.23
 
-  /@vue/compiler-sfc@3.4.21:
-    resolution: {integrity: sha512-me7epoTxYlY+2CUM7hy9PCDdpMPfIwrOvAXud2Upk10g4YLv9UBW7kL798TvMeDhPthkZ0CONNrK2GoeI1ODiQ==}
-    dependencies:
-      '@babel/parser': 7.24.1
-      '@vue/compiler-core': 3.4.21
-      '@vue/compiler-dom': 3.4.21
-      '@vue/compiler-ssr': 3.4.21
-      '@vue/shared': 3.4.21
-      estree-walker: 2.0.2
-      magic-string: 0.30.9
-      postcss: 8.4.38
-      source-map-js: 1.2.0
-    dev: true
-
-  /@vue/compiler-sfc@3.4.22:
-    resolution: {integrity: sha512-Pncp5Vc8E2Ef1o5uveO8WA1IqM7rt0R1jN8D4qitQYOUxC97iITGYA8oMInQ3UcDS7ip+SegyA2HbAEB4V6NMQ==}
+  /@vue/compiler-sfc@3.4.23:
+    resolution: {integrity: sha512-fSDTKTfzaRX1kNAUiaj8JB4AokikzStWgHooMhaxyjZerw624L+IAP/fvI4ZwMpwIh8f08PVzEnu4rg8/Npssw==}
     dependencies:
       '@babel/parser': 7.24.4
-      '@vue/compiler-core': 3.4.22
-      '@vue/compiler-dom': 3.4.22
-      '@vue/compiler-ssr': 3.4.22
-      '@vue/shared': 3.4.22
+      '@vue/compiler-core': 3.4.23
+      '@vue/compiler-dom': 3.4.23
+      '@vue/compiler-ssr': 3.4.23
+      '@vue/shared': 3.4.23
       estree-walker: 2.0.2
-      magic-string: 0.30.9
+      magic-string: 0.30.10
       postcss: 8.4.38
       source-map-js: 1.2.0
 
-  /@vue/compiler-ssr@3.4.21:
-    resolution: {integrity: sha512-M5+9nI2lPpAsgXOGQobnIueVqc9sisBFexh5yMIMRAPYLa7+5wEJs8iqOZc1WAa9WQbx9GR2twgznU8LTIiZ4Q==}
-    dependencies:
-      '@vue/compiler-dom': 3.4.21
-      '@vue/shared': 3.4.21
-    dev: true
-
-  /@vue/compiler-ssr@3.4.22:
-    resolution: {integrity: sha512-ycb2sL0SW6AkgVMrvaU/TIAEk7FQWyv/oYya44E/V9xURM+ij9Oev5bVobSS7GLJzkUieWW3SrYcK/PZpb5i4A==}
+  /@vue/compiler-ssr@3.4.23:
+    resolution: {integrity: sha512-hb6Uj2cYs+tfqz71Wj6h3E5t6OKvb4MVcM2Nl5i/z1nv1gjEhw+zYaNOV+Xwn+SSN/VZM0DgANw5TuJfxfezPg==}
     dependencies:
-      '@vue/compiler-dom': 3.4.22
-      '@vue/shared': 3.4.22
+      '@vue/compiler-dom': 3.4.23
+      '@vue/shared': 3.4.23
 
   /@vue/devtools-api@6.6.1:
     resolution: {integrity: sha512-LgPscpE3Vs0x96PzSSB4IGVSZXZBZHpfxs+ZA1d+VEPwHdOXowy/Y2CsvCAIFrf+ssVU1pD1jidj505EpUnfbA==}
     dev: false
 
-  /@vue/devtools-api@7.0.27(vue@3.4.22):
+  /@vue/devtools-api@7.0.27(vue@3.4.23):
     resolution: {integrity: sha512-BFCFCusSDcw2UcOFD/QeK7OxD1x2C/m+uAN30Q7jLKECSW53hmz0urzJmX834GuWDZX/hIxkyUKnLLfEIP1c/w==}
     dependencies:
-      '@vue/devtools-kit': 7.0.27(vue@3.4.22)
+      '@vue/devtools-kit': 7.0.27(vue@3.4.23)
     transitivePeerDependencies:
       - vue
     dev: true
 
-  /@vue/devtools-kit@7.0.27(vue@3.4.22):
+  /@vue/devtools-kit@7.0.27(vue@3.4.23):
     resolution: {integrity: sha512-/A5xM38pPCFX5Yhl/lRFAzjyK6VNsH670nww2WbjFKWqlu3I+lMxWKzQkCW6A1V8bduITgl2kHORfg2gTw6QaA==}
     peerDependencies:
       vue: ^3.0.0
@@ -3254,7 +3274,7 @@ packages:
       mitt: 3.0.1
       perfect-debounce: 1.0.0
       speakingurl: 14.0.1
-      vue: 3.4.22(typescript@5.4.5)
+      vue: 3.4.23(typescript@5.4.5)
     dev: true
 
   /@vue/devtools-shared@7.0.27:
@@ -3273,8 +3293,8 @@ packages:
     dependencies:
       '@volar/language-core': 1.11.1
       '@volar/source-map': 1.11.1
-      '@vue/compiler-dom': 3.4.22
-      '@vue/shared': 3.4.22
+      '@vue/compiler-dom': 3.4.23
+      '@vue/shared': 3.4.23
       computeds: 0.0.1
       minimatch: 9.0.4
       muggle-string: 0.3.1
@@ -3292,8 +3312,8 @@ packages:
         optional: true
     dependencies:
       '@volar/language-core': 2.1.6
-      '@vue/compiler-dom': 3.4.21
-      '@vue/shared': 3.4.21
+      '@vue/compiler-dom': 3.4.23
+      '@vue/shared': 3.4.23
       computeds: 0.0.1
       minimatch: 9.0.3
       path-browserify: 1.0.1
@@ -3301,39 +3321,35 @@ packages:
       vue-template-compiler: 2.7.16
     dev: true
 
-  /@vue/reactivity@3.4.22:
-    resolution: {integrity: sha512-+golHRRfcGoahBrhoTauFNIIAhxntRV3BI8HHqVvCdsuWivxW1MI0E9AOXVsz4H/ZlWM1ahudWTX6PhUrNR2yQ==}
+  /@vue/reactivity@3.4.23:
+    resolution: {integrity: sha512-GlXR9PL+23fQ3IqnbSQ8OQKLodjqCyoCrmdLKZk3BP7jN6prWheAfU7a3mrltewTkoBm+N7qMEb372VHIkQRMQ==}
     dependencies:
-      '@vue/shared': 3.4.22
+      '@vue/shared': 3.4.23
 
-  /@vue/runtime-core@3.4.22:
-    resolution: {integrity: sha512-cbA8lcL4g1907EdY1a1KmP5IRWfbqjgBRcgJPkF//yn96XSC1/VAJBZiAGLiyw0P77Rw2Ao7d9U51vU1GC6yUQ==}
+  /@vue/runtime-core@3.4.23:
+    resolution: {integrity: sha512-FeQ9MZEXoFzFkFiw9MQQ/FWs3srvrP+SjDKSeRIiQHIhtkzoj0X4rWQlRNHbGuSwLra6pMyjAttwixNMjc/xLw==}
     dependencies:
-      '@vue/reactivity': 3.4.22
-      '@vue/shared': 3.4.22
+      '@vue/reactivity': 3.4.23
+      '@vue/shared': 3.4.23
 
-  /@vue/runtime-dom@3.4.22:
-    resolution: {integrity: sha512-AXxRHrFkLX1y2+70CO2wDKRxW0WZcQKTOXS31AK+jZ1RLPtI6sEHVpYNfyE9WgbgXOqPtX4gfIfuoFYi8iCu2w==}
+  /@vue/runtime-dom@3.4.23:
+    resolution: {integrity: sha512-RXJFwwykZWBkMiTPSLEWU3kgVLNAfActBfWFlZd0y79FTUxexogd0PLG4HH2LfOktjRxV47Nulygh0JFXe5f9A==}
     dependencies:
-      '@vue/runtime-core': 3.4.22
-      '@vue/shared': 3.4.22
+      '@vue/runtime-core': 3.4.23
+      '@vue/shared': 3.4.23
       csstype: 3.1.3
 
-  /@vue/server-renderer@3.4.22(vue@3.4.22):
-    resolution: {integrity: sha512-okiNxiCOhJlx6IOrTZvhIVwf2UYKay0hnIPqWu4h19bkNv1gmG4Ic6U3zXY287AWF26lQuFMa515Qzc+R0aAYg==}
+  /@vue/server-renderer@3.4.23(vue@3.4.23):
+    resolution: {integrity: sha512-LDwGHtnIzvKFNS8dPJ1SSU5Gvm36p2ck8wCZc52fc3k/IfjKcwCyrWEf0Yag/2wTFUBXrqizfhK9c/mC367dXQ==}
     peerDependencies:
-      vue: 3.4.22
+      vue: 3.4.23
     dependencies:
-      '@vue/compiler-ssr': 3.4.22
-      '@vue/shared': 3.4.22
-      vue: 3.4.22(typescript@5.4.5)
+      '@vue/compiler-ssr': 3.4.23
+      '@vue/shared': 3.4.23
+      vue: 3.4.23(typescript@5.4.5)
 
-  /@vue/shared@3.4.21:
-    resolution: {integrity: sha512-PuJe7vDIi6VYSinuEbUIQgMIRZGgM8e4R+G+/dQTk0X1NEdvgvvgv7m+rfmDH1gZzyA1OjjoWskvHlfRNfQf3g==}
-    dev: true
-
-  /@vue/shared@3.4.22:
-    resolution: {integrity: sha512-cg7R9XNk4ovV3bKka/1a464O2oY0l5Fyt0rwGR4hSJRPjUJ0WVjrPdsr4W0JbUriwiM8EKcCcCjeKN5pRMs2Zg==}
+  /@vue/shared@3.4.23:
+    resolution: {integrity: sha512-wBQ0gvf+SMwsCQOyusNw/GoXPV47WGd1xB5A1Pgzy0sQ3Bi5r5xm3n+92y3gCnB3MWqnRDdvfkRGxhKtbBRNgg==}
 
   /@vue/test-utils@2.4.5:
     resolution: {integrity: sha512-oo2u7vktOyKUked36R93NB7mg2B+N7Plr8lxp2JBGwr18ch6EggFjixSCdIVVLkT6Qr0z359Xvnafc9dcKyDUg==}
@@ -3342,29 +3358,29 @@ packages:
       vue-component-type-helpers: 2.0.7
     dev: true
 
-  /@vueuse/components@10.9.0(vue@3.4.22):
+  /@vueuse/components@10.9.0(vue@3.4.23):
     resolution: {integrity: sha512-BHQpA0yIi3y7zKa1gYD0FUzLLkcRTqVhP8smnvsCK6GFpd94Nziq1XVPD7YpFeho0k5BzbBiNZF7V/DpkJ967A==}
     dependencies:
-      '@vueuse/core': 10.9.0(vue@3.4.22)
-      '@vueuse/shared': 10.9.0(vue@3.4.22)
-      vue-demi: 0.14.7(vue@3.4.22)
+      '@vueuse/core': 10.9.0(vue@3.4.23)
+      '@vueuse/shared': 10.9.0(vue@3.4.23)
+      vue-demi: 0.14.7(vue@3.4.23)
     transitivePeerDependencies:
       - '@vue/composition-api'
       - vue
     dev: true
 
-  /@vueuse/core@10.9.0(vue@3.4.22):
+  /@vueuse/core@10.9.0(vue@3.4.23):
     resolution: {integrity: sha512-/1vjTol8SXnx6xewDEKfS0Ra//ncg4Hb0DaZiwKf7drgfMsKFExQ+FnnENcN6efPen+1kIzhLQoGSy0eDUVOMg==}
     dependencies:
       '@types/web-bluetooth': 0.0.20
       '@vueuse/metadata': 10.9.0
-      '@vueuse/shared': 10.9.0(vue@3.4.22)
-      vue-demi: 0.14.7(vue@3.4.22)
+      '@vueuse/shared': 10.9.0(vue@3.4.23)
+      vue-demi: 0.14.7(vue@3.4.23)
     transitivePeerDependencies:
       - '@vue/composition-api'
       - vue
 
-  /@vueuse/integrations@10.9.0(focus-trap@7.5.4)(vue@3.4.22):
+  /@vueuse/integrations@10.9.0(focus-trap@7.5.4)(vue@3.4.23):
     resolution: {integrity: sha512-acK+A01AYdWSvL4BZmCoJAcyHJ6EqhmkQEXbQLwev1MY7NBnS+hcEMx/BzVoR9zKI+UqEPMD9u6PsyAuiTRT4Q==}
     peerDependencies:
       async-validator: '*'
@@ -3405,10 +3421,10 @@ packages:
       universal-cookie:
         optional: true
     dependencies:
-      '@vueuse/core': 10.9.0(vue@3.4.22)
-      '@vueuse/shared': 10.9.0(vue@3.4.22)
+      '@vueuse/core': 10.9.0(vue@3.4.23)
+      '@vueuse/shared': 10.9.0(vue@3.4.23)
       focus-trap: 7.5.4
-      vue-demi: 0.14.7(vue@3.4.22)
+      vue-demi: 0.14.7(vue@3.4.23)
     transitivePeerDependencies:
       - '@vue/composition-api'
       - vue
@@ -3417,10 +3433,10 @@ packages:
   /@vueuse/metadata@10.9.0:
     resolution: {integrity: sha512-iddNbg3yZM0X7qFY2sAotomgdHK7YJ6sKUvQqbvwnf7TmaVPxS4EJydcNsVejNdS8iWCtDk+fYXr7E32nyTnGA==}
 
-  /@vueuse/shared@10.9.0(vue@3.4.22):
+  /@vueuse/shared@10.9.0(vue@3.4.23):
     resolution: {integrity: sha512-Uud2IWncmAfJvRaFYzv5OHDli+FbOzxiVEQdLCKQKLyhz94PIyFC3CHcH7EDMwIn8NPtD06+PNbC/PiO0LGLtw==}
     dependencies:
-      vue-demi: 0.14.7(vue@3.4.22)
+      vue-demi: 0.14.7(vue@3.4.23)
     transitivePeerDependencies:
       - '@vue/composition-api'
       - vue
@@ -5250,13 +5266,13 @@ packages:
       - supports-color
     dev: true
 
-  /eslint-processor-vue-blocks@0.1.1(@vue/compiler-sfc@3.4.22)(eslint@8.57.0):
+  /eslint-processor-vue-blocks@0.1.1(@vue/compiler-sfc@3.4.23)(eslint@8.57.0):
     resolution: {integrity: sha512-9+dU5lU881log570oBwpelaJmOfOzSniben7IWEDRYQPPWwlvaV7NhOtsTuUWDqpYT+dtKKWPsgz4OkOi+aZnA==}
     peerDependencies:
       '@vue/compiler-sfc': ^3.3.0
       eslint: ^8.50.0
     dependencies:
-      '@vue/compiler-sfc': 3.4.22
+      '@vue/compiler-sfc': 3.4.23
       eslint: 8.57.0
     dev: true
 
@@ -6914,6 +6930,11 @@ packages:
     engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
     dev: true
 
+  /magic-string@0.30.10:
+    resolution: {integrity: sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==}
+    dependencies:
+      '@jridgewell/sourcemap-codec': 1.4.15
+
   /magic-string@0.30.8:
     resolution: {integrity: sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==}
     engines: {node: '>=12'}
@@ -6926,6 +6947,7 @@ packages:
     engines: {node: '>=12'}
     dependencies:
       '@jridgewell/sourcemap-codec': 1.4.15
+    dev: true
 
   /make-dir@4.0.0:
     resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==}
@@ -8967,6 +8989,15 @@ packages:
       which-boxed-primitive: 1.0.2
     dev: true
 
+  /unconfig@0.3.11:
+    resolution: {integrity: sha512-bV/nqePAKv71v3HdVUn6UefbsDKQWRX+bJIkiSm0+twIds6WiD2bJLWWT3i214+J/B4edufZpG2w7Y63Vbwxow==}
+    dependencies:
+      '@antfu/utils': 0.7.7
+      defu: 6.1.4
+      jiti: 1.21.0
+      mlly: 1.6.1
+    dev: true
+
   /unconfig@0.3.13:
     resolution: {integrity: sha512-N9Ph5NC4+sqtcOjPfHrRcHekBCadCXWTBzp2VYYbySOHW0PfD9XLCeXshTXjkPYwLrBr9AtSeU0CZmkYECJhng==}
     dependencies:
@@ -9135,7 +9166,7 @@ packages:
     dependencies:
       '@antfu/utils': 0.7.7
       '@rollup/pluginutils': 5.1.0
-      '@vueuse/core': 10.9.0(vue@3.4.22)
+      '@vueuse/core': 10.9.0(vue@3.4.23)
       fast-glob: 3.3.2
       local-pkg: 0.5.0
       magic-string: 0.30.8
@@ -9146,7 +9177,7 @@ packages:
       - rollup
     dev: true
 
-  /unplugin-vue-components@0.26.0(vue@3.4.22):
+  /unplugin-vue-components@0.26.0(vue@3.4.23):
     resolution: {integrity: sha512-s7IdPDlnOvPamjunVxw8kNgKNK8A5KM1YpK5j/p97jEKTjlPNrA0nZBiSfAKKlK1gWZuyWXlKL5dk3EDw874LQ==}
     engines: {node: '>=14'}
     peerDependencies:
@@ -9169,7 +9200,7 @@ packages:
       minimatch: 9.0.3
       resolve: 1.22.8
       unplugin: 1.10.1
-      vue: 3.4.22(typescript@5.4.5)
+      vue: 3.4.23(typescript@5.4.5)
     transitivePeerDependencies:
       - rollup
       - supports-color
@@ -9442,7 +9473,7 @@ packages:
       '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.24.3)
       '@babel/plugin-transform-typescript': 7.24.1(@babel/core@7.24.3)
       '@vue/babel-plugin-jsx': 1.2.2(@babel/core@7.24.3)
-      '@vue/compiler-dom': 3.4.21
+      '@vue/compiler-dom': 3.4.23
       kolorist: 1.8.0
       magic-string: 0.30.8
       vite: 5.2.9
@@ -9450,13 +9481,13 @@ packages:
       - supports-color
     dev: true
 
-  /vite-svg-loader@5.1.0(vue@3.4.22):
+  /vite-svg-loader@5.1.0(vue@3.4.23):
     resolution: {integrity: sha512-M/wqwtOEjgb956/+m5ZrYT/Iq6Hax0OakWbokj8+9PXOnB7b/4AxESHieEtnNEy7ZpjsjYW1/5nK8fATQMmRxw==}
     peerDependencies:
       vue: '>=3.2.13'
     dependencies:
       svgo: 3.2.0
-      vue: 3.4.22(typescript@5.4.5)
+      vue: 3.4.23(typescript@5.4.5)
     dev: true
 
   /vite@5.2.9:
@@ -9511,17 +9542,17 @@ packages:
       '@shikijs/core': 1.3.0
       '@shikijs/transformers': 1.3.0
       '@types/markdown-it': 13.0.7
-      '@vitejs/plugin-vue': 5.0.4(vite@5.2.9)(vue@3.4.22)
-      '@vue/devtools-api': 7.0.27(vue@3.4.22)
-      '@vueuse/core': 10.9.0(vue@3.4.22)
-      '@vueuse/integrations': 10.9.0(focus-trap@7.5.4)(vue@3.4.22)
+      '@vitejs/plugin-vue': 5.0.4(vite@5.2.9)(vue@3.4.23)
+      '@vue/devtools-api': 7.0.27(vue@3.4.23)
+      '@vueuse/core': 10.9.0(vue@3.4.23)
+      '@vueuse/integrations': 10.9.0(focus-trap@7.5.4)(vue@3.4.23)
       focus-trap: 7.5.4
       mark.js: 8.11.1
       minisearch: 6.3.0
       postcss: 8.4.38
       shiki: 1.3.0
       vite: 5.2.9
-      vue: 3.4.22(typescript@5.4.5)
+      vue: 3.4.23(typescript@5.4.5)
     transitivePeerDependencies:
       - '@algolia/client-search'
       - '@types/node'
@@ -9616,7 +9647,7 @@ packages:
     resolution: {integrity: sha512-7e12Evdll7JcTIocojgnCgwocX4WzIYStGClBQ+QuWPinZo/vQolv2EMq4a3lg16TKfwWafLimG77bxb56UauA==}
     dev: true
 
-  /vue-demi@0.14.7(vue@3.4.22):
+  /vue-demi@0.14.7(vue@3.4.23):
     resolution: {integrity: sha512-EOG8KXDQNwkJILkx/gPcoL/7vH+hORoBaKgGe+6W7VFMvCYJfmF2dGbvgDroVnI8LU7/kTu8mbjRZGBU1z9NTA==}
     engines: {node: '>=12'}
     hasBin: true
@@ -9628,7 +9659,7 @@ packages:
       '@vue/composition-api':
         optional: true
     dependencies:
-      vue: 3.4.22(typescript@5.4.5)
+      vue: 3.4.23(typescript@5.4.5)
 
   /vue-eslint-parser@9.4.2(eslint@8.57.0):
     resolution: {integrity: sha512-Ry9oiGmCAK91HrKMtCrKFWmSFWvYkpGglCeFAIqDdr9zdXmMMpJOmUJS7WWsW7fX81h6mwHmUZCQQ1E0PkSwYQ==}
@@ -9648,13 +9679,13 @@ packages:
       - supports-color
     dev: true
 
-  /vue-router@4.3.0(vue@3.4.22):
-    resolution: {integrity: sha512-dqUcs8tUeG+ssgWhcPbjHvazML16Oga5w34uCUmsk7i0BcnskoLGwjpa15fqMr2Fa5JgVBrdL2MEgqz6XZ/6IQ==}
+  /vue-router@4.3.1(vue@3.4.23):
+    resolution: {integrity: sha512-D0h3oyP6vp28BOvxv2hVpiqFTjTJizCf1BuMmCibc8UW0Ll/N80SWqDd/hqPMaZfzW1j+s2s+aTRyBIP9ElzOw==}
     peerDependencies:
       vue: ^3.2.0
     dependencies:
       '@vue/devtools-api': 6.6.1
-      vue: 3.4.22(typescript@5.4.5)
+      vue: 3.4.23(typescript@5.4.5)
     dev: false
 
   /vue-template-compiler@2.7.16:
@@ -9688,19 +9719,19 @@ packages:
       typescript: 5.4.5
     dev: true
 
-  /vue@3.4.22(typescript@5.4.5):
-    resolution: {integrity: sha512-CIx7NiP+n5WHBCG/fDNaUPP4qbQ5CIa8XIHZE3HpfS/rb2vmSIsp74BxsZyrrGKF0vHW3GoToqP3l0hzrMTecw==}
+  /vue@3.4.23(typescript@5.4.5):
+    resolution: {integrity: sha512-X1y6yyGJ28LMUBJ0k/qIeKHstGd+BlWQEOT40x3auJFTmpIhpbKLgN7EFsqalnJXq1Km5ybDEsp6BhuWKciUDg==}
     peerDependencies:
       typescript: '*'
     peerDependenciesMeta:
       typescript:
         optional: true
     dependencies:
-      '@vue/compiler-dom': 3.4.22
-      '@vue/compiler-sfc': 3.4.22
-      '@vue/runtime-dom': 3.4.22
-      '@vue/server-renderer': 3.4.22(vue@3.4.22)
-      '@vue/shared': 3.4.22
+      '@vue/compiler-dom': 3.4.23
+      '@vue/compiler-sfc': 3.4.23
+      '@vue/runtime-dom': 3.4.23
+      '@vue/server-renderer': 3.4.23(vue@3.4.23)
+      '@vue/shared': 3.4.23
       typescript: 5.4.5
 
   /w3c-xmlserializer@5.0.0:

+ 2 - 1
src/directives/index.ts

@@ -2,5 +2,6 @@ import { vLog } from './vLog'
 import { vLightHelper } from './vLightHelper'
 import { vAlwaysLookAt } from './vAlwaysLookAt'
 import { vDistanceTo } from './vDistanceTo'
+import { vRotate } from './vRotate'
 
-export { vLog, vLightHelper, vAlwaysLookAt, vDistanceTo }
+export { vLog, vLightHelper, vAlwaysLookAt, vDistanceTo, vRotate }

+ 40 - 0
src/directives/vRotate.ts

@@ -0,0 +1,40 @@
+import { ref } from 'vue'
+import { Quaternion, Vector3 } from 'three'
+import type { TresObject } from '../types'
+import { useLogger, useRenderLoop } from '../composables'
+
+const { logWarning } = useLogger()
+
+export const vRotate = {
+  mounted: (
+    el: TresObject,
+    binding: {
+      arg: 'x' | 'y' | 'z'
+      value: number
+      modifiers: Partial<{ x: boolean, y: boolean, z: boolean }>
+    },
+  ) => {
+    if (el.isCamera) {
+      logWarning(`Rotate the ${el.type} is not a good idea`)
+      return
+    }
+    const radiansPerFrame = binding.value ?? 0.01
+    const x = ref(binding.modifiers.x || binding.arg === 'x' ? 1 : 0)
+    const y = ref(binding.modifiers.y || binding.arg === 'y' ? 1 : 0)
+    const z = ref(binding.modifiers.z || binding.arg === 'z' ? 1 : 0)
+
+    if (x.value + y.value + z.value === 0) {
+      x.value = 1
+      y.value = 1
+    }
+
+    const quaternion = new Quaternion().setFromAxisAngle(new Vector3(x.value, y.value, z.value)
+      .normalize(), radiansPerFrame)
+
+    const { onLoop } = useRenderLoop()
+
+    onLoop(() => {
+      el.applyQuaternion(quaternion)
+    })
+  },
+}