Răsfoiți Sursa

feat: model and animation recipe (#1082)

* feat: add model animation examples and documentation

* fix: remove unused watch on animations and update thumbnail path in model animation documentation

* fix: add type annotation for TresObject in HologramCube component
Alvaro Saburido 1 săptămână în urmă
părinte
comite
078d7bce3c

+ 18 - 0
docs/app/components/examples/model-animation/Experience.vue

@@ -0,0 +1,18 @@
+<script setup lang="ts">
+import { Environment, OrbitControls } from '@tresjs/cientos'
+import KnightCharacter from './Knight.vue'
+</script>
+
+<template>
+  <TresPerspectiveCamera
+    :position="[3, 2, 3]"
+    :look-at="[0, 1, 0]"
+  />
+  <OrbitControls :target="[0, 1, 0]" />
+  <TresAmbientLight :intensity="1" />
+  <Suspense>
+    <Environment preset="sunset" background :blur="1" />
+  </Suspense>
+  <KnightCharacter />
+  <!-- Render the animated model here -->
+</template>

+ 35 - 0
docs/app/components/examples/model-animation/Knight.vue

@@ -0,0 +1,35 @@
+<script setup lang="ts">
+import { useAnimations, useGLTF } from '@tresjs/cientos'
+import { computed } from 'vue'
+import type { AnimationAction } from 'three'
+import { LoopOnce } from 'three'
+
+const { state: model, nodes } = useGLTF('/models/knight/Knight.glb')
+const rig = computed(() => nodes.value.Rig)
+
+const animations = computed(() => model.value?.animations || [])
+
+const { actions } = useAnimations(animations, rig)
+const currentAction = ref<AnimationAction>()
+
+watch(actions, (actions) => {
+  if (!actions) { return }
+
+  // Play the idle animation by default
+  currentAction.value = actions.Cheer
+  currentAction.value?.setLoop(LoopOnce, 1)
+  currentAction.value?.play()
+
+  const nextAnimation = actions.Idle as AnimationAction
+
+  if (nextAnimation) {
+    nextAnimation.setEffectiveWeight(1)
+    nextAnimation.enabled = true
+    nextAnimation.play()
+  }
+}, { immediate: true })
+</script>
+
+<template>
+  <primitive v-if="rig" :object="rig" />
+</template>

+ 33 - 0
docs/app/components/examples/model-animation/index.vue

@@ -0,0 +1,33 @@
+<script setup lang="ts">
+import { TresCanvas } from '@tresjs/core'
+import TheExperience from './Experience.vue'
+
+import { useProgress } from '@tresjs/cientos'
+
+const { hasFinishLoading, progress } = await useProgress()
+</script>
+
+<template>
+  <SceneWrapper>
+    <Transition
+      name="fade-overlay"
+      enter-active-class="opacity-1 transition-opacity duration-200"
+      leave-active-class="opacity-0 transition-opacity duration-200"
+    >
+      <div
+        v-show="!hasFinishLoading"
+        class="absolute bg-default t-0 l-0 w-full h-full z-20 flex justify-center items-center font-mono"
+      >
+        <div class="w-200px">
+          Loading... {{ progress }} %
+          <i class="i-lucide-loading animate-rotate-in"></i>
+        </div>
+      </div>
+    </Transition>
+    <TresCanvas
+      clear-color="#82DBC5"
+    >
+      <TheExperience />
+    </TresCanvas>
+  </SceneWrapper>
+</template>

+ 2 - 2
docs/app/components/examples/web-gpu/HologramCube.vue

@@ -1,5 +1,5 @@
 <script setup lang="ts">
-import { isMesh } from '@tresjs/core'
+import { isMesh, type TresObject } from '@tresjs/core'
 import { useGLTF } from '@tresjs/cientos'
 import { add, cameraProjectionMatrix, cameraViewMatrix, color, Fn, hash, mix, normalView, positionWorld, sin, timerGlobal, uniform, varying, vec3, vec4 } from 'three/tsl'
 import { AdditiveBlending, DoubleSide, MeshBasicNodeMaterial } from 'three/webgpu'
@@ -46,7 +46,7 @@ material.colorNode = Fn(() => {
 })()
 
 watch(model, (newModel) => {
-  newModel?.traverse((child) => {
+  newModel?.traverse((child: TresObject) => {
     if (isMesh(child)) {
       child.material = material
     }

+ 173 - 0
docs/content/4.cookbook/2.model-animation.md

@@ -0,0 +1,173 @@
+---
+title: Model Animation
+description: Learn how to animate 3D models in TresJS
+thumbnail: /recipes/model-n-animations/model-n-animations.png
+---
+
+::examples-model-animation
+::
+
+Let's bring your 3D models to life with animations in TresJS. This guide covers loading animated models and controlling their playback.
+
+## Where to find models? 
+
+You can find quality 3D models for your projects in various online repositories. Here are some hand picked sources from the TresJS community:
+
+- [poly.pizza](https://poly.pizza/) - A collection of free 3D models.
+- [Pmndrs Marketplace](https://market.pmnd.rs/) - A marketplace for 3D assets. All free
+- [KayKit Character Packs](https://kaylousberg.itch.io/) - Free and paid character packs. Animated, all CC0, a personal favorite of ours.
+
+For this tutorial we will use a simplified version of the **KayKit Knight character**, you can download it directly from <UButton variant="ghost" icon="i-lucide-arrow-down" download external :to="/models/knight/Knight.glb">here</UButton>.
+
+![Knight model](/recipes/model-n-animations/kaykit-simplified-knight.png)
+
+## Loading Animated Models
+
+::steps
+
+### Install cientos
+
+If you haven't already, install the `@tresjs/cientos` package, which provides components for loading 3D models.
+
+   ```bash
+   npm install @tresjs/cientos
+   ```
+
+### Load the Model
+
+Use the `useGLTF` composable from `@tresjs/cientos` to load your animated model. Add the downloaded GLB file to your public directory in a subfolder like `/models/knight/`.
+
+```vue [Knight.vue]
+<script setup lang="ts">
+import { useGLTF } from '@tresjs/cientos'
+
+const { state: model, nodes } = useGLTF('/models/knight/Knight.glb')
+</script>
+```
+
+::read-more{TO="https://cientos.tresjs.org/guide/loaders/use-gltf.html"}
+Learn more about the `useGLTF` composable.
+::
+
+### Add Rig to the Scene
+
+The Rig is the root object that contains the entire model and its animations. You can access it from the individual nodes.
+
+::tip
+The Rig might be named differently depending on the model. Check the model's structure to find the correct root object.
+::
+
+```vue [Knight.vue]
+<script setup lang="ts">
+import { useGLTF } from '@tresjs/cientos'
+
+const { state: model, nodes } = useGLTF('/models/knight/Knight.glb')
+
+// We access the rig from the individual nodes
+const rig = computed(() => nodes.value.Rig)
+</script>
+
+<template>
+   <primitive v-if="rig" :object="rig" />
+</template>
+```
+::
+
+
+## Animation Control
+
+::steps
+
+### Use the `useAnimations` Composable
+
+The `useAnimations` composable helps manage and play animations from your model. It takes the animations array and the rig as parameters and returns the `AnimationClips` (actions).
+
+```vue [Knight.vue]
+<script setup lang="ts">
+import { useGLTF, useAnimations } from '@tresjs/cientos'
+
+const { state: model, nodes } = useGLTF('/models/knight/Knight.glb')
+
+const animations = computed(() => model.value?.animations || [])
+const rig = computed(() => nodes.value.Rig)
+
+const { actions } = useAnimations(animations, rig)
+</script>
+```
+
+::read-more{TO="https://cientos.tresjs.org/guide/abstractions/use-animations.html"}
+Learn more about the `useAnimations` composable.
+::
+
+### Play an Animation
+
+You can play an animation by calling the `play` method on the desired action. For example, to play the "Cheer" animation:
+
+```ts
+const { actions } = useAnimations(animations, rig)
+
+actions.value.Cheer?.play()
+```
+
+### Set animation loop
+
+You can set the loop mode of an animation using the `setLoop` method. For example, to make the "Cheer" animation loop indefinitely:
+
+```ts
+actions.value.Cheer?.setLoop(THREE.LoopRepeat, Infinity)
+actions.value.Cheer?.play()
+```
+
+### Smooth Animation Transitions
+
+To create smooth transitions between animations, use the `fadeIn` and `fadeOut` methods. This prevents abrupt changes and creates more natural character movement:
+
+```vue [Knight.vue]
+<script setup lang="ts">
+import { useGLTF, useAnimations } from '@tresjs/cientos'
+import type { AnimationAction } from 'three'
+
+const { state: model, nodes } = useGLTF('/models/knight/Knight.glb')
+const animations = computed(() => model.value?.animations || [])
+const rig = computed(() => nodes.value.Rig)
+const { actions } = useAnimations(animations, rig)
+
+let currentAction = ref<AnimationAction | null>(null)
+
+const transitionToAnimation = (animationName: string, duration = 0.5) => {
+  const nextAction = actions.value[animationName]
+  if (!nextAction) return
+
+  // Fade out current animation
+  if (currentAction.value) {
+    currentAction.value.fadeOut(duration)
+  }
+
+  // Fade in new animation
+  nextAction.reset()
+  nextAction.setEffectiveWeight(1)
+  nextAction.play()
+  nextAction.fadeIn(duration)
+
+  currentAction.value = nextAction
+}
+
+// Example: Transition from Idle to Cheer
+const playCheerAnimation = () => {
+  transitionToAnimation('Cheer', 0.3)
+}
+
+const playIdleAnimation = () => {
+  transitionToAnimation('Idle', 0.3)
+}
+</script>
+```
+
+**Key points about animation transitions:**
+
+- `fadeOut(duration)` gradually reduces the animation's influence over the specified duration
+- `fadeIn(duration)` gradually increases the animation's influence over the specified duration
+- `reset()` resets the animation to its starting frame
+- `setEffectiveWeight(1)` ensures the animation has full influence when active
+- Shorter durations (0.1-0.3s) work well for quick actions, longer ones (0.5-1s) for smoother character transitions
+::

+ 5 - 0
docs/nuxt.config.ts

@@ -34,6 +34,11 @@ export default defineNuxtConfig({
     'nuxt-llms',
   ],
 
+  image: {
+    quality: 80,
+    format: ['webp', 'png', 'jpg'],
+  },
+
   router: {
     options: {
       strict: true,

+ 1 - 1
docs/package.json

@@ -19,7 +19,7 @@
     "@nuxt/content": "^3.6.3",
     "@nuxt/image": "^1.11.0",
     "@nuxt/ui-pro": "^3.3.0",
-    "@tresjs/cientos": "5.0.0-next.0",
+    "@tresjs/cientos": "5.0.0-alpha.1",
     "@tresjs/core": "workspace:^",
     "better-sqlite3": "^12.2.0",
     "nuxt": "^4.0.3",

BIN
docs/public/models/knight/Knight.glb


BIN
docs/public/models/knight/knight_texture.png


BIN
docs/public/recipes/model-n-animations/kaykit-simplified-knight.png


BIN
docs/public/recipes/model-n-animations/model-n-animations.png


+ 2 - 1
package.json

@@ -81,7 +81,7 @@
   "devDependencies": {
     "@release-it/conventional-changelog": "^10.0.0",
     "@stackblitz/sdk": "^1.11.0",
-    "@tresjs/cientos": "5.0.0-next.0",
+    "@tresjs/cientos": "5.0.0-alpha.1",
     "@tresjs/eslint-config": "^1.4.0",
     "@tresjs/leches": "1.0.0-next.0",
     "@types/three": "^0.179.0",
@@ -129,6 +129,7 @@
       "vue-demi"
     ],
     "overrides": {
+      "ipx": "^3.0.3",
       "vue": "^3.5.21",
       "vue-router": "^4.5.1"
     }

+ 43 - 110
pnpm-lock.yaml

@@ -6,6 +6,7 @@ settings:
 
 overrides:
   unimport: 4.1.1
+  ipx: ^3.0.3
   vue: ^3.5.21
   vue-router: ^4.5.1
 
@@ -33,8 +34,8 @@ importers:
         specifier: ^1.11.0
         version: 1.11.0
       '@tresjs/cientos':
-        specifier: 5.0.0-next.0
-        version: 5.0.0-next.0(@tresjs/core@5.0.0-next.6(three@0.179.1)(typescript@5.9.2)(vue@3.5.21(typescript@5.9.2)))(@types/three@0.179.0)(three@0.179.1)(typescript@5.9.2)(vue@3.5.21(typescript@5.9.2))
+        specifier: 5.0.0-alpha.1
+        version: 5.0.0-alpha.1(@tresjs/core@5.0.0-next.6(three@0.179.1)(typescript@5.9.2)(vue@3.5.21(typescript@5.9.2)))(@types/three@0.179.0)(three@0.179.1)(vue@3.5.21(typescript@5.9.2))
       '@tresjs/eslint-config':
         specifier: ^1.4.0
         version: 1.4.0(@typescript-eslint/utils@8.42.0(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2))(@vue/compiler-sfc@3.5.21)(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2)(vitest@3.2.4)
@@ -171,8 +172,8 @@ importers:
         specifier: ^3.3.0
         version: 3.3.0(@babel/parser@7.28.3)(@netlify/blobs@9.1.2)(change-case@5.4.4)(db0@0.3.2(better-sqlite3@12.2.0))(embla-carousel@8.6.0)(focus-trap@7.6.5)(ioredis@5.6.1)(jwt-decode@4.0.0)(magicast@0.3.5)(typescript@5.9.2)(vite@7.1.4(@types/node@24.1.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))(vue-router@4.5.1(vue@3.5.21(typescript@5.9.2)))(vue@3.5.21(typescript@5.9.2))(zod@3.25.76)
       '@tresjs/cientos':
-        specifier: 5.0.0-next.0
-        version: 5.0.0-next.0(@tresjs/core@)(@types/three@0.179.0)(three@0.179.1)(typescript@5.9.2)(vue@3.5.21(typescript@5.9.2))
+        specifier: 5.0.0-alpha.1
+        version: 5.0.0-alpha.1(@tresjs/core@)(@types/three@0.179.0)(three@0.179.1)(vue@3.5.21(typescript@5.9.2))
       '@tresjs/core':
         specifier: workspace:^
         version: link:..
@@ -1197,9 +1198,8 @@ packages:
     resolution: {integrity: sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w==}
     engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
 
-  '@fastify/accept-negotiator@1.1.0':
-    resolution: {integrity: sha512-OIHZrb2ImZ7XG85HXOONLcJWGosv7sIvM2ifAPQVhg9Lv7qdmMBNVaai4QTdyuaqbKM5eO6sLSQOYI7wEQeCJQ==}
-    engines: {node: '>=14'}
+  '@fastify/accept-negotiator@2.0.1':
+    resolution: {integrity: sha512-/c/TW2bO/v9JeEgoD/g1G5GxGeCF1Hafdf79WPmUlgYiBXummY0oX3VVq4yFkKKVBKDNlaDUYoab7g38RpPqCQ==}
 
   '@fastify/busboy@2.1.1':
     resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==}
@@ -2645,6 +2645,13 @@ packages:
   '@tootallnate/quickjs-emscripten@0.23.0':
     resolution: {integrity: sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==}
 
+  '@tresjs/cientos@5.0.0-alpha.1':
+    resolution: {integrity: sha512-UyR/Yu5BakVhm4arovch+pTGys6pJ0z3O3HBYPYIBbN8iM5LDzGDvWMEqDH5SmUVJG8pYxRAQGgt0s8JjRYMwQ==}
+    peerDependencies:
+      '@tresjs/core': '>=5.0.0'
+      three: '>=0.133'
+      vue: ^3.5.21
+
   '@tresjs/cientos@5.0.0-next.0':
     resolution: {integrity: sha512-Sj8CyYoOpFU95MnvTUwauz2ce3T39tpHCFX15XKzgQF+WGBhWhEGfkvjh35tTgNUZFPMB8BwUeGlTN5CYolaAQ==}
     peerDependencies:
@@ -3678,33 +3685,6 @@ packages:
   bare-events@2.6.0:
     resolution: {integrity: sha512-EKZ5BTXYExaNqi3I3f9RtEsaI/xBSGjE0XZCZilPzFAV/goswFHuPd9jEZlPIZ/iNZJwDSao9qRiScySz7MbQg==}
 
-  bare-fs@4.1.6:
-    resolution: {integrity: sha512-25RsLF33BqooOEFNdMcEhMpJy8EoR88zSMrnOQOaM3USnOK2VmaJ1uaQEwPA6AQjrv1lXChScosN6CzbwbO9OQ==}
-    engines: {bare: '>=1.16.0'}
-    peerDependencies:
-      bare-buffer: '*'
-    peerDependenciesMeta:
-      bare-buffer:
-        optional: true
-
-  bare-os@3.6.1:
-    resolution: {integrity: sha512-uaIjxokhFidJP+bmmvKSgiMzj2sV5GPHaZVAIktcxcpCyBFFWO+YlikVAdhmUo2vYFvFhOXIAlldqV29L8126g==}
-    engines: {bare: '>=1.14.0'}
-
-  bare-path@3.0.0:
-    resolution: {integrity: sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==}
-
-  bare-stream@2.6.5:
-    resolution: {integrity: sha512-jSmxKJNJmHySi6hC42zlZnq00rga4jjxcgNZjY9N5WlOe/iOoGRtdwGsHzQv2RlH2KOYMwGUXhf2zXd32BA9RA==}
-    peerDependencies:
-      bare-buffer: '*'
-      bare-events: '*'
-    peerDependenciesMeta:
-      bare-buffer:
-        optional: true
-      bare-events:
-        optional: true
-
   base64-js@1.5.1:
     resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
 
@@ -5487,8 +5467,8 @@ packages:
     resolution: {integrity: sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==}
     engines: {node: '>= 12'}
 
-  ipx@2.1.1:
-    resolution: {integrity: sha512-XuM9FEGOT+/45mfAWZ5ykwkZ/oE7vWpd1iWjRffMWlwAYIRzb/xD6wZhQ4BzmPMX6Ov5dqK0wUyD0OEN9oWT6g==}
+  ipx@3.1.1:
+    resolution: {integrity: sha512-7Xnt54Dco7uYkfdAw0r2vCly3z0rSaVhEXMzPvl3FndsTVm5p26j+PO+gyinkYmcsEUvX2Rh7OGK7KzYWRu6BA==}
     hasBin: true
 
   iron-webcrypto@1.2.1:
@@ -6356,9 +6336,6 @@ packages:
     resolution: {integrity: sha512-OhYaY5sDsIka7H7AtijtI9jwGYLyl29eQn/W623DiN/MIv5sUqc4g7BIDThX+gb7di9f6xK02nkp8sdfFWZLTg==}
     engines: {node: '>=10'}
 
-  node-addon-api@6.1.0:
-    resolution: {integrity: sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==}
-
   node-addon-api@7.1.1:
     resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==}
 
@@ -7349,10 +7326,6 @@ packages:
   setprototypeof@1.2.0:
     resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
 
-  sharp@0.32.6:
-    resolution: {integrity: sha512-KyLTWwgcR9Oe4d9HwCwNM2l7+J0dUQwn/yf7S0EnTtb0eVS4RxO0eUSvxPtzT4F3SY+C4K6fqdv/DO27sJ/v/w==}
-    engines: {node: '>=14.15.0'}
-
   sharp@0.34.3:
     resolution: {integrity: sha512-eX2IQ6nFohW4DbvHIOLRB3MHFpYqaqvXd3Tp5e/T/dSH83fxaNJQRvDMhASmkNTsNTVF2/OOopzRCt7xokgPfg==}
     engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
@@ -7689,9 +7662,6 @@ packages:
   tar-fs@2.1.3:
     resolution: {integrity: sha512-090nwYJDmlhwFwEW3QQl+vaNnxsO2yVsd45eTKRBzSzu+hlb1w2K9inVq5b0ngXuLVqQ4ApvsUHHnu/zQNkWAg==}
 
-  tar-fs@3.1.0:
-    resolution: {integrity: sha512-5Mty5y/sOF1YWj1J6GiBodjlDc05CUR8PKXrsnFAiSG0xA+GHeWLovaZPYUDXkH/1iKRf2+M5+OrRgzC7O9b7w==}
-
   tar-stream@2.2.0:
     resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==}
     engines: {node: '>=6'}
@@ -9618,7 +9588,7 @@ snapshots:
       '@eslint/core': 0.15.2
       levn: 0.4.1
 
-  '@fastify/accept-negotiator@1.1.0':
+  '@fastify/accept-negotiator@2.0.1':
     optional: true
 
   '@fastify/busboy@2.1.1': {}
@@ -10362,7 +10332,7 @@ snapshots:
       std-env: 3.9.0
       ufo: 1.6.1
     optionalDependencies:
-      ipx: 2.1.1(@netlify/blobs@9.1.2)(db0@0.3.2(better-sqlite3@12.2.0))(ioredis@5.6.1)
+      ipx: 3.1.1(@netlify/blobs@9.1.2)(db0@0.3.2(better-sqlite3@12.2.0))(ioredis@5.6.1)
     transitivePeerDependencies:
       - '@azure/app-configuration'
       - '@azure/cosmos'
@@ -10378,7 +10348,6 @@ snapshots:
       - '@vercel/blob'
       - '@vercel/kv'
       - aws4fetch
-      - bare-buffer
       - db0
       - idb-keyval
       - ioredis
@@ -11478,10 +11447,10 @@ snapshots:
 
   '@tootallnate/quickjs-emscripten@0.23.0': {}
 
-  '@tresjs/cientos@5.0.0-next.0(@tresjs/core@)(@types/three@0.179.0)(three@0.179.1)(typescript@5.9.2)(vue@3.5.21(typescript@5.9.2))':
+  '@tresjs/cientos@5.0.0-alpha.1(@tresjs/core@)(@types/three@0.179.0)(three@0.179.1)(vue@3.5.21(typescript@5.9.2))':
     dependencies:
       '@tresjs/core': 'link:'
-      '@vueuse/core': 12.8.2(typescript@5.9.2)
+      '@vueuse/core': 13.9.0(vue@3.5.21(typescript@5.9.2))
       camera-controls: 2.10.1(three@0.179.1)
       stats-gl: 2.4.2(@types/three@0.179.0)(three@0.179.1)
       stats.js: 0.17.0
@@ -11493,11 +11462,26 @@ snapshots:
       - '@react-three/fiber'
       - '@types/three'
       - react
-      - typescript
 
-  '@tresjs/cientos@5.0.0-next.0(@tresjs/core@5.0.0-next.6(three@0.179.1)(typescript@5.9.2)(vue@3.5.21(typescript@5.9.2)))(@types/three@0.179.0)(three@0.179.1)(typescript@5.9.2)(vue@3.5.21(typescript@5.9.2))':
+  '@tresjs/cientos@5.0.0-alpha.1(@tresjs/core@5.0.0-next.6(three@0.179.1)(typescript@5.9.2)(vue@3.5.21(typescript@5.9.2)))(@types/three@0.179.0)(three@0.179.1)(vue@3.5.21(typescript@5.9.2))':
     dependencies:
       '@tresjs/core': 5.0.0-next.6(three@0.179.1)(typescript@5.9.2)(vue@3.5.21(typescript@5.9.2))
+      '@vueuse/core': 13.9.0(vue@3.5.21(typescript@5.9.2))
+      camera-controls: 2.10.1(three@0.179.1)
+      stats-gl: 2.4.2(@types/three@0.179.0)(three@0.179.1)
+      stats.js: 0.17.0
+      three: 0.179.1
+      three-custom-shader-material: 5.4.0(three@0.179.1)
+      three-stdlib: 2.36.0(three@0.179.1)
+      vue: 3.5.21(typescript@5.9.2)
+    transitivePeerDependencies:
+      - '@react-three/fiber'
+      - '@types/three'
+      - react
+
+  '@tresjs/cientos@5.0.0-next.0(@tresjs/core@)(@types/three@0.179.0)(three@0.179.1)(typescript@5.9.2)(vue@3.5.21(typescript@5.9.2))':
+    dependencies:
+      '@tresjs/core': 'link:'
       '@vueuse/core': 12.8.2(typescript@5.9.2)
       camera-controls: 2.10.1(three@0.179.1)
       stats-gl: 2.4.2(@types/three@0.179.0)(three@0.179.1)
@@ -12779,28 +12763,6 @@ snapshots:
   bare-events@2.6.0:
     optional: true
 
-  bare-fs@4.1.6:
-    dependencies:
-      bare-events: 2.6.0
-      bare-path: 3.0.0
-      bare-stream: 2.6.5(bare-events@2.6.0)
-    optional: true
-
-  bare-os@3.6.1:
-    optional: true
-
-  bare-path@3.0.0:
-    dependencies:
-      bare-os: 3.6.1
-    optional: true
-
-  bare-stream@2.6.5(bare-events@2.6.0):
-    dependencies:
-      streamx: 2.22.1
-    optionalDependencies:
-      bare-events: 2.6.0
-    optional: true
-
   base64-js@1.5.1: {}
 
   basic-ftp@5.0.5: {}
@@ -14876,21 +14838,21 @@ snapshots:
       jsbn: 1.1.0
       sprintf-js: 1.1.3
 
-  ipx@2.1.1(@netlify/blobs@9.1.2)(db0@0.3.2(better-sqlite3@12.2.0))(ioredis@5.6.1):
+  ipx@3.1.1(@netlify/blobs@9.1.2)(db0@0.3.2(better-sqlite3@12.2.0))(ioredis@5.6.1):
     dependencies:
-      '@fastify/accept-negotiator': 1.1.0
+      '@fastify/accept-negotiator': 2.0.1
       citty: 0.1.6
       consola: 3.4.2
       defu: 6.1.4
       destr: 2.0.5
       etag: 1.8.1
-      h3: 1.15.3
+      h3: 1.15.4
       image-meta: 0.2.1
       listhen: 1.9.0
       ofetch: 1.4.1
-      pathe: 1.1.2
-      sharp: 0.32.6
-      svgo: 3.3.2
+      pathe: 2.0.3
+      sharp: 0.34.3
+      svgo: 4.0.0
       ufo: 1.6.1
       unstorage: 1.16.1(@netlify/blobs@9.1.2)(db0@0.3.2(better-sqlite3@12.2.0))(ioredis@5.6.1)
       xss: 1.0.15
@@ -14909,7 +14871,6 @@ snapshots:
       - '@vercel/blob'
       - '@vercel/kv'
       - aws4fetch
-      - bare-buffer
       - db0
       - idb-keyval
       - ioredis
@@ -15981,9 +15942,6 @@ snapshots:
     dependencies:
       semver: 7.7.2
 
-  node-addon-api@6.1.0:
-    optional: true
-
   node-addon-api@7.1.1: {}
 
   node-domexception@1.0.0: {}
@@ -17296,20 +17254,6 @@ snapshots:
 
   setprototypeof@1.2.0: {}
 
-  sharp@0.32.6:
-    dependencies:
-      color: 4.2.3
-      detect-libc: 2.0.4
-      node-addon-api: 6.1.0
-      prebuild-install: 7.1.3
-      semver: 7.7.2
-      simple-get: 4.0.1
-      tar-fs: 3.1.0
-      tunnel-agent: 0.6.0
-    transitivePeerDependencies:
-      - bare-buffer
-    optional: true
-
   sharp@0.34.3:
     dependencies:
       color: 4.2.3
@@ -17699,17 +17643,6 @@ snapshots:
       pump: 3.0.3
       tar-stream: 2.2.0
 
-  tar-fs@3.1.0:
-    dependencies:
-      pump: 3.0.3
-      tar-stream: 3.1.7
-    optionalDependencies:
-      bare-fs: 4.1.6
-      bare-path: 3.0.0
-    transitivePeerDependencies:
-      - bare-buffer
-    optional: true
-
   tar-stream@2.2.0:
     dependencies:
       bl: 4.1.0