فهرست منبع

Merge branch 'main' into release/core-v1.5.1-cientos-1.5.0

Alvaro 2 سال پیش
والد
کامیت
3c357ed017
47فایلهای تغییر یافته به همراه2110 افزوده شده و 151 حذف شده
  1. 7 1
      .vscode/settings.json
  2. 61 2
      apps/playground/astro.config.mjs
  3. 9 1
      apps/playground/package.json
  4. BIN
      apps/playground/public/animations.png
  5. BIN
      apps/playground/public/gltf-model.png
  6. 5 0
      apps/playground/public/logo-dark.svg
  7. 5 0
      apps/playground/public/logo.svg
  8. BIN
      apps/playground/public/materials.png
  9. BIN
      apps/playground/public/portal-journey.png
  10. BIN
      apps/playground/public/textures.png
  11. BIN
      apps/playground/public/transform-controls.png
  12. BIN
      apps/playground/public/tres-basic.png
  13. BIN
      apps/playground/public/tres-donut.png
  14. 38 0
      apps/playground/src/components/BasicAnimations.vue
  15. 0 62
      apps/playground/src/components/Card.astro
  16. 3 0
      apps/playground/src/components/ExperimentInfo.vue
  17. 28 0
      apps/playground/src/components/Header.astro
  18. 126 0
      apps/playground/src/components/Materials.vue
  19. 13 0
      apps/playground/src/components/SuspenseWrapper.vue
  20. 50 0
      apps/playground/src/components/Textures.vue
  21. 21 0
      apps/playground/src/components/TheInfo.astro
  22. 2 4
      apps/playground/src/components/TresDonut.vue
  23. 20 0
      apps/playground/src/components/portal-journey/TheExperience.vue
  24. 43 0
      apps/playground/src/components/portal-journey/TheFireFlies.vue
  25. 83 0
      apps/playground/src/components/portal-journey/ThePortal.vue
  26. 7 0
      apps/playground/src/components/portal-journey/shaders/fireflies/fragment.glsl
  27. 16 0
      apps/playground/src/components/portal-journey/shaders/fireflies/vertex.glsl
  28. 101 0
      apps/playground/src/components/portal-journey/shaders/portal/fragment.glsl
  29. 11 0
      apps/playground/src/components/portal-journey/shaders/portal/vertex.glsl
  30. 8 0
      apps/playground/src/components/textures/Textures.vue
  31. 62 0
      apps/playground/src/components/textures/TheExperience.vue
  32. 75 0
      apps/playground/src/layouts/ExperimentLayout.astro
  33. 78 29
      apps/playground/src/layouts/Layout.astro
  34. 34 7
      apps/playground/src/pages/index.astro
  35. 61 0
      apps/playground/src/pages/vue/animations.mdx
  36. 59 0
      apps/playground/src/pages/vue/basic.mdx
  37. 0 11
      apps/playground/src/pages/vue/gltf-model.astro
  38. 40 0
      apps/playground/src/pages/vue/gltf-model.mdx
  39. 147 0
      apps/playground/src/pages/vue/materials.mdx
  40. 334 0
      apps/playground/src/pages/vue/portal-journey.mdx
  41. 85 0
      apps/playground/src/pages/vue/textures.mdx
  42. 0 11
      apps/playground/src/pages/vue/transform-controls.astro
  43. 111 0
      apps/playground/src/pages/vue/transform-controls.mdx
  44. 0 11
      apps/playground/src/pages/vue/tres-basic.astro
  45. 0 11
      apps/playground/src/pages/vue/tres-donut.astro
  46. 41 0
      apps/playground/src/pages/vue/tres-donut.mdx
  47. 326 1
      pnpm-lock.yaml

+ 7 - 1
.vscode/settings.json

@@ -16,5 +16,11 @@
   "scss.lint.unknownAtRules": "ignore",
   "css.lint.unknownAtRules": "ignore",
   "eslint.workingDirectories": ["apps/", "packages/"],
-  "testing.automaticallyOpenPeekView": "never"
+  "testing.automaticallyOpenPeekView": "never",
+  "files.associations": {
+    "*.mdx": "markdown"
+  },
+  "[astro]": {
+    "editor.defaultFormatter": "astro-build.astro-vscode"
+  }
 }

+ 61 - 2
apps/playground/astro.config.mjs

@@ -1,9 +1,68 @@
 import { defineConfig } from 'astro/config'
-
+import glsl from 'vite-plugin-glsl'
+import UnoCSS from 'unocss/astro'
+import {
+  presetAttributify,
+  presetIcons,
+  presetTypography,
+  presetUno,
+  presetWebFonts,
+  transformerDirectives,
+  transformerVariantGroup,
+} from 'unocss'
+import presetDaisy from 'unocss-preset-daisy'
 // https://astro.build/config
 import vue from '@astrojs/vue'
 
+// https://astro.build/config
+import mdx from '@astrojs/mdx'
+
 // https://astro.build/config
 export default defineConfig({
-  integrations: [vue({ appEntrypoint: '/src/pages/_app' })],
+  vite: {
+    ssr: {
+      noExternal: ['@kidonng/daisyui'],
+    },
+    plugins: [glsl()],
+  },
+  integrations: [
+    vue({
+      appEntrypoint: '/src/pages/_app',
+    }),
+    UnoCSS({
+      presets: [
+        presetUno(),
+        presetAttributify(),
+        presetIcons({
+          scale: 1.2,
+          warn: true,
+          extraProperties: {
+            display: 'inline-block',
+            'vertical-align': 'middle',
+            // ...
+          },
+        }),
+        presetTypography({
+          cssExtend: {
+            blockquote: {
+              padding: '1rem',
+              'border-left': `8px solid #888 !important`,
+              background: '#e8e8e8',
+            },
+          },
+        }),
+        presetWebFonts({
+          fonts: {
+            sans: 'DM Sans',
+            serif: 'DM Serif Display',
+            mono: 'DM Mono',
+          },
+        }),
+        presetDaisy(),
+      ],
+      transformers: [transformerDirectives(), transformerVariantGroup()],
+      safelist: 'prose prose-sm m-auto text-left'.split(' '),
+    }),
+    mdx(),
+  ],
 })

+ 9 - 1
apps/playground/package.json

@@ -20,13 +20,21 @@
     "astro": "astro"
   },
   "dependencies": {
+    "@astrojs/mdx": "^0.14.0",
     "@astrojs/vue": "^1.2.2",
     "astro": "^1.9.2",
+    "astro-seo": "^0.7.0",
     "vue": "^3.2.45"
   },
   "devDependencies": {
+    "@iconify-json/carbon": "^1.1.13",
+    "@iconify-json/logos": "^1.1.22",
+    "@kidonng/daisyui": "^2.31.0",
     "@tresjs/cientos": "workspace:^1.4.0",
     "@tresjs/core": "workspace:^1.5.0",
-    "three": "^0.148.0"
+    "three": "^0.148.0",
+    "unocss": "^0.48.0",
+    "unocss-preset-daisy": "^1.2.0",
+    "vite-plugin-glsl": "^1.0.1"
   }
 }

BIN
apps/playground/public/animations.png


BIN
apps/playground/public/gltf-model.png


+ 5 - 0
apps/playground/public/logo-dark.svg

@@ -0,0 +1,5 @@
+<svg width="44" height="10" viewBox="0 0 44 10" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M5.14255 1.42916C5.53095 0.781817 6.46913 0.781816 6.85753 1.42915L11.0913 8.4855C11.4913 9.15203 11.0111 10 10.2338 10H1.76623C0.988935 10 0.508822 9.15203 0.908736 8.4855L5.14255 1.42916Z" fill="#82DBC5"/>
+<rect x="19" y="1" width="9" height="9" rx="1" fill="#f2f2f2"/>
+<circle cx="39.5" cy="5.5" r="4.5" fill="#EFAC35"/>
+</svg>

+ 5 - 0
apps/playground/public/logo.svg

@@ -0,0 +1,5 @@
+<svg width="44" height="10" viewBox="0 0 44 10" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M5.14255 1.42916C5.53095 0.781817 6.46913 0.781816 6.85753 1.42915L11.0913 8.4855C11.4913 9.15203 11.0111 10 10.2338 10H1.76623C0.988935 10 0.508822 9.15203 0.908736 8.4855L5.14255 1.42916Z" fill="#82DBC5"/>
+<rect x="19" y="1" width="9" height="9" rx="1" fill="#4F4F4F"/>
+<circle cx="39.5" cy="5.5" r="4.5" fill="#EFAC35"/>
+</svg>

BIN
apps/playground/public/materials.png


BIN
apps/playground/public/portal-journey.png


BIN
apps/playground/public/textures.png


BIN
apps/playground/public/transform-controls.png


BIN
apps/playground/public/tres-basic.png


BIN
apps/playground/public/tres-donut.png


+ 38 - 0
apps/playground/src/components/BasicAnimations.vue

@@ -0,0 +1,38 @@
+<script setup lang="ts">
+import { ShallowRef, shallowRef } from 'vue'
+
+import { useRenderLoop, TresInstance } from '@tresjs/core'
+import { OrbitControls } from '@tresjs/cientos'
+
+const boxRef: ShallowRef<TresInstance | null> = shallowRef(null)
+
+const { onLoop } = useRenderLoop()
+
+onLoop(({ delta, elapsed }) => {
+  if (boxRef.value) {
+    boxRef.value.rotation.y += delta
+    boxRef.value.rotation.z = elapsed * 0.2
+  }
+})
+</script>
+
+<template>
+  <TresCanvas
+    clear-color="#82DBC5"
+    shadows
+    alpha
+    window-size
+    power-preference="high-performance"
+    physically-correct-lights
+  >
+    <OrbitControls />
+    <TresPerspectiveCamera :position="[1, 2, 5]" :fov="45" :aspect="1" :near="0.1" :far="1000" />
+    <TresScene>
+      <TresMesh ref="boxRef" :scale="1" cast-shadow>
+        <TresBoxGeometry :args="[1, 1, 1]" />
+        <TresMeshNormalMaterial />
+      </TresMesh>
+      <TresDirectionalLight :position="[0, 2, 4]" :intensity="2" cast-shadow />
+    </TresScene>
+  </TresCanvas>
+</template>

+ 0 - 62
apps/playground/src/components/Card.astro

@@ -1,62 +0,0 @@
----
-export interface Props {
-	title: string;
-	body: string;
-	href: string;
-}
-
-const { href, title, body } = Astro.props;
----
-
-<li class="link-card">
-	<a href={href}>
-		<h2>
-			{title}
-			<span>&rarr;</span>
-		</h2>
-		<p>
-			{body}
-		</p>
-	</a>
-</li>
-<style>
-	.link-card {
-		list-style: none;
-		display: flex;
-		padding: 0.15rem;
-		background-color: white;
-		background-image: var(--accent-gradient);
-		background-size: 400%;
-		border-radius: 0.5rem;
-		background-position: 100%;
-		transition: background-position 0.6s cubic-bezier(0.22, 1, 0.36, 1);
-		box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1);
-	}
-
-	.link-card > a {
-		width: 100%;
-		text-decoration: none;
-		line-height: 1.4;
-		padding: 1rem 1.3rem;
-		border-radius: 0.35rem;
-		color: #111;
-		background-color: white;
-		opacity: 0.8;
-	}
-	h2 {
-		margin: 0;
-		font-size: 1.25rem;
-		transition: color 0.6s cubic-bezier(0.22, 1, 0.36, 1);
-	}
-	p {
-		margin-top: 0.5rem;
-		margin-bottom: 0;
-		color: #444;
-	}
-	.link-card:is(:hover, :focus-within) {
-		background-position: 0;
-	}
-	.link-card:is(:hover, :focus-within) h2 {
-		color: rgb(var(--accent));
-	}
-</style>

+ 3 - 0
apps/playground/src/components/ExperimentInfo.vue

@@ -0,0 +1,3 @@
+<script setup lang="ts"></script>
+
+<template>Awiwi</template>

+ 28 - 0
apps/playground/src/components/Header.astro

@@ -0,0 +1,28 @@
+---
+import Logo from '/logo.svg'
+
+export interface Props {
+  title: string
+  visible: boolean
+}
+
+const { visible = false, title } = Astro.props
+---
+
+<header class={`fixed top-0 z-10 w-full bg-white bg-opacity-60 py-4 ${visible ? 'visible' : 'hidden'}`}>
+  <div class="px-4 sm:px-0 container mx-auto flex justify-between">
+    <div class="flex">
+      <img src={Logo} class="mr-8" />
+      <a class="font-bold" href="/" title="Home">{title}</a>
+    </div>
+    <ul class="flex">
+      <a href="https://tresjs.org/" target="_blank" class="i-carbon-document"></a>
+    </ul>
+  </div>
+</header>
+
+<style scoped>
+  header {
+    backdrop-filter: blur(10px);
+  }
+</style>

+ 126 - 0
apps/playground/src/components/Materials.vue

@@ -0,0 +1,126 @@
+<script setup lang="ts">
+import { OrbitControls, Plane, useTweakPane } from '@tresjs/cientos'
+import {
+  BasicShadowMap,
+  Color,
+  CubeTextureLoader,
+  MeshBasicMaterial,
+  MeshLambertMaterial,
+  MeshMatcapMaterial,
+  MeshNormalMaterial,
+  MeshPhongMaterial,
+  MeshPhysicalMaterial,
+  MeshStandardMaterial,
+  MeshToonMaterial,
+  NoToneMapping,
+  sRGBEncoding,
+} from 'three'
+import { shallowReactive, shallowRef } from 'vue'
+
+const { pane } = useTweakPane()
+const state = shallowReactive({
+  clearColor: '#4f4f4f',
+  shadows: true,
+  alpha: false,
+  physicallyCorrectLights: true,
+  shadowMapType: BasicShadowMap,
+  outputEncoding: sRGBEncoding,
+  toneMapping: NoToneMapping,
+})
+
+const cubeTextureLoader = new CubeTextureLoader()
+
+const environmentMap = cubeTextureLoader.load([
+  'https://raw.githubusercontent.com/Tresjs/assets/main/textures/environmentMap/px.jpg',
+  'https://raw.githubusercontent.com/Tresjs/assets/main/textures/environmentMap/nx.jpg',
+  'https://raw.githubusercontent.com/Tresjs/assets/main/textures/environmentMap/py.jpg',
+  'https://raw.githubusercontent.com/Tresjs/assets/main/textures/environmentMap/ny.jpg',
+  'https://raw.githubusercontent.com/Tresjs/assets/main/textures/environmentMap/pz.jpg',
+  'https://raw.githubusercontent.com/Tresjs/assets/main/textures/environmentMap/nz.jpg',
+])
+
+const materialState = shallowReactive({
+  color: '#008080',
+  metalness: 0.5,
+  wireframe: false,
+})
+
+const sphereRef = shallowRef()
+pane
+  .addInput(materialState, 'color', {
+    label: 'Color',
+  })
+  .on('change', (ev: any) => {
+    sphereRef.value.material.color = new Color(ev.value)
+  })
+
+pane
+  .addInput(materialState, 'wireframe', {
+    label: 'Wireframe',
+  })
+  .on('change', (ev: any) => {
+    sphereRef.value.material.wireframe = ev.value
+  })
+
+const materialProps = ['metalness', 'roughness']
+
+materialProps.forEach(element => {
+  pane
+    .addBlade({
+      view: 'slider',
+      label: element,
+      min: 0,
+      max: 1,
+      value: 0.5,
+    })
+    .on('change', (ev: any) => {
+      materialState[element] = ev.value
+      sphereRef.value.material[element] = ev.value
+    })
+})
+
+pane
+  .addBlade({
+    view: 'list',
+    label: 'Materials',
+    options: [
+      { text: 'MeshBasicMaterial', value: MeshBasicMaterial },
+      { text: 'MeshToonMaterial', value: MeshToonMaterial },
+      /*    { text: 'MeshDepthMaterial', value: MeshDepthMaterial },
+      { text: 'MeshDistanceMaterial', value: MeshDistanceMaterial }, */
+      { text: 'MeshLambertMaterial', value: MeshLambertMaterial },
+      { text: 'MeshMatcapMaterial', value: MeshMatcapMaterial },
+      { text: 'MeshNormalMaterial', value: MeshNormalMaterial },
+      { text: 'MeshPhongMaterial', value: MeshPhongMaterial },
+      { text: 'MeshPhysicalMaterial', value: MeshPhysicalMaterial },
+      { text: 'MeshStandardMaterial', value: MeshStandardMaterial },
+    ],
+    value: MeshToonMaterial,
+  })
+  .on('change', ev => {
+    sphereRef.value.material = new ev.value(materialState)
+
+    if (ev.value === MeshStandardMaterial || ev.value === MeshPhysicalMaterial) {
+      sphereRef.value.material.envMap = environmentMap
+    }
+  })
+</script>
+<template>
+  <TresCanvas v-bind="state">
+    <TresPerspectiveCamera :position="[3, 3, 5]" :fov="45" :aspect="1" :near="0.1" :far="1000" />
+    <OrbitControls />
+    <TresScene>
+      <TresMesh ref="sphereRef" :position="[0, 1, 0]" cast-shadow recieve-shadow>
+        <TresSphereGeometry :args="[1, 32, 32]" />
+        <TresMeshToonMaterial :color="materialState.color" />
+      </TresMesh>
+      <Plane :args="[10, 10]" recieve-shadow>
+        <TresMeshToonMaterial color="#222" />
+      </Plane>
+      <TresDirectionalLight :position="[-3, 4, 4]" :intensity="2" cast-shadow />
+      <TresDirectionalLight :position="[3, 4, 0]" :intensity="0.5" cast-shadow />
+
+      <TresAmbientLight :intensity="1" />
+    </TresScene>
+  </TresCanvas>
+</template>

+ 13 - 0
apps/playground/src/components/SuspenseWrapper.vue

@@ -0,0 +1,13 @@
+<script setup lang="ts">
+defineProps<{
+  component: any
+}>()
+
+/* import Textures from './Textures.vue' */
+</script>
+<template>
+  <pre>{{ component }}.</pre>
+  <Suspense>
+    <component :is="component.__name" />
+  </Suspense>
+</template>

+ 50 - 0
apps/playground/src/components/Textures.vue

@@ -0,0 +1,50 @@
+<script setup lang="ts">
+import { Ref, ref } from 'vue'
+
+import { useTexture, useRenderLoop } from '@tresjs/core'
+import { OrbitControls } from '@tresjs/cientos'
+import { TresInstance } from '@tresjs/core/dist/types'
+
+const pbrTexture = await useTexture({
+  map: 'https://raw.githubusercontent.com/Tresjs/assets/main/textures/black-rock/Rock035_2K_Displacement.jpg',
+  displacementMap:
+    'https://raw.githubusercontent.com/Tresjs/assets/main/textures/black-rock/Rock035_2K_Displacement.jpg',
+  roughnessMap: 'https://raw.githubusercontent.com/Tresjs/assets/main/textures/black-rock/Rock035_2K_Roughness.jpg',
+  normalMap: 'https://raw.githubusercontent.com/Tresjs/assets/main/textures/black-rock/Rock035_2K_NormalGL.jpg',
+  ambientOcclusion:
+    'https://raw.githubusercontent.com/Tresjs/assets/main/textures/black-rock/Rock035_2K_AmbientOcclusion.jpg',
+})
+
+const sphereRef: Ref<TresInstance | null> = ref(null)
+
+const { onLoop } = useRenderLoop()
+
+onLoop(({ delta }) => {
+  // I will run at every frame ~ 60FPS (depending of your monitor)
+  if (sphereRef.value) {
+    sphereRef.value.rotation.y = delta
+  }
+})
+</script>
+
+<template>
+  <TresCanvas
+    clear-color="#82DBC5"
+    shadows
+    alpha
+    window-size
+    power-preference="high-performance"
+    preserve-drawing-buffer
+    physically-correct-lights
+  >
+    <OrbitControls />
+    <TresPerspectiveCamera :position="[1, 2, 5]" :fov="45" :aspect="1" :near="0.1" :far="1000" />
+    <TresScene>
+      <TresMesh ref="sphereRef" :scale="1" cast-shadow>
+        <TresSphereGeometry :args="[1, 100, 100]" />
+        <TresMeshStandardMaterial v-bind="pbrTexture" displacement-scale="0.2" />
+      </TresMesh>
+      <TresDirectionalLight :position="[0, 2, 4]" :intensity="2" cast-shadow />
+    </TresScene>
+  </TresCanvas>
+</template>

+ 21 - 0
apps/playground/src/components/TheInfo.astro

@@ -0,0 +1,21 @@
+---
+/* const { path } = Astro.params
+
+console.log(Astro) */
+---
+
+<div class="fixed bottom-0 right-0">
+  <div class="dropdown dropdown-top dropdown-end p-4 w-full flex justify-end z-60">
+    <label
+      tabindex={0}
+      class="btn btn-circle important:(bg-white border-white text-gray-600 dark:text-light-200 hover:bg-gray-100) cursor-pointer"
+      ><i class="i-carbon-information"></i></label
+    >
+    <div
+      tabindex={0}
+      class="mb-8 dropdown-content px-4 shadow bg-base-100 rounded-box pb-8 mr-4 z-20 overflow-scroll max-h-screen-md"
+    >
+      <div class="prose"><slot /></div>
+    </div>
+  </div>
+</div>

+ 2 - 4
apps/playground/src/components/TresDonut.vue

@@ -1,18 +1,16 @@
 <script setup lang="ts">
 import { reactive } from 'vue'
 
-import { OrbitControls } from '@tresjs/cientos'
-
 const state = reactive({
   shadows: true,
   alpha: false,
+  clearColor: '#4f4f4f',
 })
 </script>
 
 <template>
   <TresCanvas v-bind="state">
-    <OrbitControls />
-    <TresPerspectiveCamera :position="[8, 8, 8]" :fov="45" :aspect="1" :near="0.1" :far="1000" />
+    <TresPerspectiveCamera :position="[0, 0, 6]" :fov="75" :aspect="1" :near="0.1" :far="1000" />
     <TresScene>
       <TresMesh>
         <TresTorusGeometry :args="[1, 0.5, 16, 32]" />

+ 20 - 0
apps/playground/src/components/portal-journey/TheExperience.vue

@@ -0,0 +1,20 @@
+<script setup lang="ts">
+import ThePortal from './ThePortal.vue'
+import { OrbitControls } from '@tresjs/cientos'
+import TheFireFlies from './TheFireFlies.vue'
+</script>
+
+<template>
+  <Suspense>
+    <TresCanvas clear-color="#201919" shadows alpha window-size power-preference="high-performance">
+      <OrbitControls />
+      <TresPerspectiveCamera :position="[5, 5, 5]" :fov="45" :aspect="1" :near="0.1" :far="1000" />
+      <TresScene>
+        <TresFog :args="['#201919', 0.1, 75]" />
+        <ThePortal />
+        <TheFireFlies />
+        <TresAmbientLight :position="[10, 10, 10]" :intensity="1.5" color="#00ff00" />
+      </TresScene>
+    </TresCanvas>
+  </Suspense>
+</template>

+ 43 - 0
apps/playground/src/components/portal-journey/TheFireFlies.vue

@@ -0,0 +1,43 @@
+<script setup lang="ts">
+import { useRenderLoop } from '@tresjs/core'
+import { AdditiveBlending } from 'three'
+import FirefliesVertex from './shaders/fireflies/vertex.glsl'
+import FirefliesFragment from './shaders/fireflies/fragment.glsl'
+
+const shader = {
+  transparent: true,
+  blending: AdditiveBlending,
+  depthWrite: false,
+
+  vertexShader: FirefliesVertex,
+  fragmentShader: FirefliesFragment,
+  uniforms: {
+    uSize: { value: 100 },
+    uPixelRatio: { value: Math.min(window.devicePixelRatio, 2) },
+    uTime: { value: 0 },
+  },
+}
+
+const firefliesCount = 60
+const positionArray = new Float32Array(firefliesCount * 3)
+const scaleArray = new Float32Array(firefliesCount)
+
+for (let i = 0; i < firefliesCount; i++) {
+  positionArray[i * 3 + 0] = (Math.random() - 0.5) * 4
+  positionArray[i * 3 + 1] = Math.random() * 4
+  positionArray[i * 3 + 2] = (Math.random() - 0.5) * 4
+  scaleArray[i] = Math.random()
+}
+
+const { onLoop } = useRenderLoop()
+
+onLoop(({ elapsed }) => {
+  shader.uniforms.uTime.value = elapsed
+})
+</script>
+<template>
+  <TresPoints>
+    <TresBufferGeometry :position="[positionArray, 3]" :a-scale="[scaleArray, 1]" />
+    <TresShaderMaterial v-bind="shader" />
+  </TresPoints>
+</template>

+ 83 - 0
apps/playground/src/components/portal-journey/ThePortal.vue

@@ -0,0 +1,83 @@
+<script setup lang="ts">
+import { sRGBEncoding, DoubleSide, MeshBasicMaterial, ShaderMaterial, Color, Mesh } from 'three'
+import { useRenderLoop, useTexture } from '@tresjs/core'
+import { useGLTF, useTweakPane } from '@tresjs/cientos'
+
+import PortalVertex from './shaders/portal/vertex.glsl'
+import PortalFragment from './shaders/portal/fragment.glsl'
+
+const experiment = {
+  portalColorStart: '#7030eb',
+  portalColorEnd: '#ddc0ff',
+}
+
+const { pane } = useTweakPane()
+
+const portalCtrls = pane.addFolder({ title: 'Portal' })
+portalCtrls
+  .addInput(experiment, 'portalColorStart', {
+    label: 'color start',
+    min: 0,
+    max: 1,
+    step: 0.01,
+  })
+  .on('change', ({ value }) => {
+    portalLightMaterial.uniforms.uColorStart.value.set(value)
+  })
+portalCtrls
+  .addInput(experiment, 'portalColorEnd', {
+    label: 'color end',
+    min: 0,
+    max: 1,
+    step: 0.01,
+  })
+  .on('change', ({ value }) => {
+    portalLightMaterial.uniforms.uColorEnd.value.set(value)
+  })
+
+const { scene: portal } = await useGLTF(
+  'https://raw.githubusercontent.com/Tresjs/assets/main/models/gltf/portal/portal.glb',
+  {
+    draco: true,
+  },
+)
+
+const bakedTexture = await useTexture([
+  'https://raw.githubusercontent.com/Tresjs/assets/main/models/gltf/portal/baked.jpg',
+])
+
+bakedTexture.flipY = false
+bakedTexture.encoding = sRGBEncoding
+
+// Baked material
+const bakedMaterial = new MeshBasicMaterial({
+  map: bakedTexture,
+  side: DoubleSide,
+})
+
+const portalLightMaterial = new ShaderMaterial({
+  uniforms: {
+    uTime: { value: 0 },
+    uColorStart: { value: new Color(experiment.portalColorStart) },
+    uColorEnd: { value: new Color(experiment.portalColorEnd) },
+  },
+  vertexShader: PortalVertex,
+  fragmentShader: PortalFragment,
+  side: DoubleSide,
+})
+
+const portalObj = portal
+const bakedMesh = portalObj.children.find(child => child.name === 'baked')
+;(bakedMesh as Mesh).material = bakedMaterial
+const portalCircle = portalObj.children.find(child => child.name === 'portalCircle')
+;(portalCircle as Mesh).material = portalLightMaterial
+
+const { onLoop } = useRenderLoop()
+
+onLoop(({ _delta, elapsed }) => {
+  portalLightMaterial.uniforms.uTime.value = elapsed
+})
+</script>
+<template>
+  <TresMesh v-bind="portal" />
+</template>

+ 7 - 0
apps/playground/src/components/portal-journey/shaders/fireflies/fragment.glsl

@@ -0,0 +1,7 @@
+void main()
+{
+  float distanceToCenter = distance(gl_PointCoord, vec2(0.5));
+  float strength = 0.05 / distanceToCenter - 0.1;
+
+  gl_FragColor = vec4(1.0, 1.0, 1.0, strength);
+}

+ 16 - 0
apps/playground/src/components/portal-journey/shaders/fireflies/vertex.glsl

@@ -0,0 +1,16 @@
+uniform float uPixelRatio;
+uniform float uSize;
+uniform float uTime;
+attribute float aScale;
+
+void main()
+{
+    vec4 modelPosition = modelMatrix * vec4(position, 1.0);
+    modelPosition.y += sin(uTime + modelPosition.x * 100.0) * aScale * 0.2;
+    vec4 viewPosition = viewMatrix * modelPosition;
+    vec4 projectionPosition = projectionMatrix * viewPosition;
+
+    gl_Position = projectionPosition;
+    gl_PointSize = aScale * uSize * uPixelRatio;
+    gl_PointSize *= (1.0 / - viewPosition.z);
+}

+ 101 - 0
apps/playground/src/components/portal-journey/shaders/portal/fragment.glsl

@@ -0,0 +1,101 @@
+varying vec2 vUv;
+uniform float uTime;
+uniform vec3 uColorStart;
+uniform vec3 uColorEnd;
+
+//	Classic Perlin 3D Noise 
+//	by Stefan Gustavson
+//
+vec4 permute(vec4 x){return mod(((x*34.0)+1.0)*x, 289.0);}
+vec4 taylorInvSqrt(vec4 r){return 1.79284291400159 - 0.85373472095314 * r;}
+vec3 fade(vec3 t) {return t*t*t*(t*(t*6.0-15.0)+10.0);}
+
+float cnoise(vec3 P){
+  vec3 Pi0 = floor(P); // Integer part for indexing
+  vec3 Pi1 = Pi0 + vec3(1.0); // Integer part + 1
+  Pi0 = mod(Pi0, 289.0);
+  Pi1 = mod(Pi1, 289.0);
+  vec3 Pf0 = fract(P); // Fractional part for interpolation
+  vec3 Pf1 = Pf0 - vec3(1.0); // Fractional part - 1.0
+  vec4 ix = vec4(Pi0.x, Pi1.x, Pi0.x, Pi1.x);
+  vec4 iy = vec4(Pi0.yy, Pi1.yy);
+  vec4 iz0 = Pi0.zzzz;
+  vec4 iz1 = Pi1.zzzz;
+
+  vec4 ixy = permute(permute(ix) + iy);
+  vec4 ixy0 = permute(ixy + iz0);
+  vec4 ixy1 = permute(ixy + iz1);
+
+  vec4 gx0 = ixy0 / 7.0;
+  vec4 gy0 = fract(floor(gx0) / 7.0) - 0.5;
+  gx0 = fract(gx0);
+  vec4 gz0 = vec4(0.5) - abs(gx0) - abs(gy0);
+  vec4 sz0 = step(gz0, vec4(0.0));
+  gx0 -= sz0 * (step(0.0, gx0) - 0.5);
+  gy0 -= sz0 * (step(0.0, gy0) - 0.5);
+
+  vec4 gx1 = ixy1 / 7.0;
+  vec4 gy1 = fract(floor(gx1) / 7.0) - 0.5;
+  gx1 = fract(gx1);
+  vec4 gz1 = vec4(0.5) - abs(gx1) - abs(gy1);
+  vec4 sz1 = step(gz1, vec4(0.0));
+  gx1 -= sz1 * (step(0.0, gx1) - 0.5);
+  gy1 -= sz1 * (step(0.0, gy1) - 0.5);
+
+  vec3 g000 = vec3(gx0.x,gy0.x,gz0.x);
+  vec3 g100 = vec3(gx0.y,gy0.y,gz0.y);
+  vec3 g010 = vec3(gx0.z,gy0.z,gz0.z);
+  vec3 g110 = vec3(gx0.w,gy0.w,gz0.w);
+  vec3 g001 = vec3(gx1.x,gy1.x,gz1.x);
+  vec3 g101 = vec3(gx1.y,gy1.y,gz1.y);
+  vec3 g011 = vec3(gx1.z,gy1.z,gz1.z);
+  vec3 g111 = vec3(gx1.w,gy1.w,gz1.w);
+
+  vec4 norm0 = taylorInvSqrt(vec4(dot(g000, g000), dot(g010, g010), dot(g100, g100), dot(g110, g110)));
+  g000 *= norm0.x;
+  g010 *= norm0.y;
+  g100 *= norm0.z;
+  g110 *= norm0.w;
+  vec4 norm1 = taylorInvSqrt(vec4(dot(g001, g001), dot(g011, g011), dot(g101, g101), dot(g111, g111)));
+  g001 *= norm1.x;
+  g011 *= norm1.y;
+  g101 *= norm1.z;
+  g111 *= norm1.w;
+
+  float n000 = dot(g000, Pf0);
+  float n100 = dot(g100, vec3(Pf1.x, Pf0.yz));
+  float n010 = dot(g010, vec3(Pf0.x, Pf1.y, Pf0.z));
+  float n110 = dot(g110, vec3(Pf1.xy, Pf0.z));
+  float n001 = dot(g001, vec3(Pf0.xy, Pf1.z));
+  float n101 = dot(g101, vec3(Pf1.x, Pf0.y, Pf1.z));
+  float n011 = dot(g011, vec3(Pf0.x, Pf1.yz));
+  float n111 = dot(g111, Pf1);
+
+  vec3 fade_xyz = fade(Pf0);
+  vec4 n_z = mix(vec4(n000, n100, n010, n110), vec4(n001, n101, n011, n111), fade_xyz.z);
+  vec2 n_yz = mix(n_z.xy, n_z.zw, fade_xyz.y);
+  float n_xyz = mix(n_yz.x, n_yz.y, fade_xyz.x); 
+  return 2.2 * n_xyz;
+}
+
+void main() 
+{
+    float speed = 0.1;
+    // Displace the UV coordinates by a noise value
+    vec2 displacedUv = vUv + cnoise(vec3(vUv* 5.0, uTime * speed));
+    // Get the color from the texture
+    float strength = cnoise(vec3(displacedUv * 5.0, uTime * speed * 2.0));
+
+    // Outer Glow
+
+    float outerGlow = distance(vUv, vec2(0.5)) * 5.0 - 1.4;
+    strength += outerGlow;
+
+    strength += step(- 0.2, strength) * 0.8;
+
+    strength = clamp(strength, 0.0, 1.0);
+
+    vec3 color = mix(uColorStart, uColorEnd, strength);
+
+    gl_FragColor = vec4(color, 1.0);
+}

+ 11 - 0
apps/playground/src/components/portal-journey/shaders/portal/vertex.glsl

@@ -0,0 +1,11 @@
+varying vec2 vUv;
+
+void main() 
+{
+    vec4 modelPosition = modelMatrix * vec4(position, 1.0);
+    vec4 viewPosition = viewMatrix * modelPosition;
+    vec4 projectionPosition = projectionMatrix * viewPosition;
+
+    gl_Position = projectionPosition;
+    vUv = uv;
+}

+ 8 - 0
apps/playground/src/components/textures/Textures.vue

@@ -0,0 +1,8 @@
+<script setup lang="ts">
+import TheExperience from './TheExperience.vue'
+</script>
+<template>
+  <Suspense>
+    <TheExperience />
+  </Suspense>
+</template>

+ 62 - 0
apps/playground/src/components/textures/TheExperience.vue

@@ -0,0 +1,62 @@
+<script setup lang="ts">
+import { Ref, ref } from 'vue'
+
+import { useTexture, useRenderLoop } from '@tresjs/core'
+import { OrbitControls, Plane } from '@tresjs/cientos'
+import { TresInstance } from '@tresjs/core/dist/types'
+
+const pbrTexture = await useTexture({
+  map: 'https://raw.githubusercontent.com/Tresjs/assets/main/textures/black-rock/Rock035_2K_Displacement.jpg',
+  displacementMap:
+    'https://raw.githubusercontent.com/Tresjs/assets/main/textures/black-rock/Rock035_2K_Displacement.jpg',
+  roughnessMap: 'https://raw.githubusercontent.com/Tresjs/assets/main/textures/black-rock/Rock035_2K_Roughness.jpg',
+  normalMap: 'https://raw.githubusercontent.com/Tresjs/assets/main/textures/black-rock/Rock035_2K_NormalGL.jpg',
+  ambientOcclusion:
+    'https://raw.githubusercontent.com/Tresjs/assets/main/textures/black-rock/Rock035_2K_AmbientOcclusion.jpg',
+})
+
+const blackRock = await useTexture({
+  map: 'https://raw.githubusercontent.com/Tresjs/assets/main/textures/black-rock/Rock035_2K_Color.jpg',
+  displacementMap:
+    'https://raw.githubusercontent.com/Tresjs/assets/main/textures/black-rock/Rock035_2K_Displacement.jpg',
+  roughnessMap: 'https://raw.githubusercontent.com/Tresjs/assets/main/textures/black-rock/Rock035_2K_Roughness.jpg',
+  normalMap: 'https://raw.githubusercontent.com/Tresjs/assets/main/textures/black-rock/Rock035_2K_NormalGL.jpg',
+  ambientOcclusion:
+    'https://raw.githubusercontent.com/Tresjs/assets/main/textures/black-rock/Rock035_2K_AmbientOcclusion.jpg',
+})
+
+const sphereRef: Ref<TresInstance | null> = ref(null)
+
+const { onLoop } = useRenderLoop()
+
+onLoop(({ delta }) => {
+  // I will run at every frame ~ 60FPS (depending of your monitor)
+  if (sphereRef.value) {
+    sphereRef.value.rotation.y += delta
+  }
+})
+</script>
+
+<template>
+  <TresCanvas
+    clear-color="#82DBC5"
+    shadows
+    alpha
+    window-size
+    power-preference="high-performance"
+    preserve-drawing-buffer
+  >
+    <OrbitControls />
+    <TresPerspectiveCamera :position="[11, 11, 11]" :fov="45" :aspect="1" :near="0.1" :far="1000" />
+    <TresScene>
+      <TresMesh ref="sphereRef" :position="[0, 4, 0]" :scale="1" cast-shadow>
+        <TresSphereGeometry :args="[1, 500, 500]" />
+        <TresMeshStandardMaterial v-bind="blackRock" displacement-scale="0.2" />
+      </TresMesh>
+      <Plane :args="[10, 10, 500, 500]">
+        <TresMeshStandardMaterial v-bind="pbrTexture" displacement-scale="0.6" />
+      </Plane>
+      <TresDirectionalLight :position="[0, 2, 4]" :intensity="1" cast-shadow />
+    </TresScene>
+  </TresCanvas>
+</template>

+ 75 - 0
apps/playground/src/layouts/ExperimentLayout.astro

@@ -0,0 +1,75 @@
+---
+import { SEO } from 'astro-seo'
+import '@kidonng/daisyui/index.css'
+
+const { frontmatter } = Astro.props
+---
+
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="UTF-8" />
+    <meta name="viewport" content="width=device-width" />
+    <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
+    <meta name="generator" content={Astro.generator} />
+    <SEO
+      title={frontmatter.title}
+      description={frontmatter.description}
+      openGraph={{
+        basic: {
+          title: frontmatter.title,
+          type: 'website',
+          image: frontmatter.thumbnail,
+        },
+        image: {
+          alt: 'TresJS',
+        },
+      }}
+      twitter={{
+        creator: '@alvarosabu',
+      }}
+      extend={{
+        // extending the default link tags
+        link: [{ rel: 'icon', href: '/favicon.ico' }],
+        // extending the default meta tags
+        meta: [
+          {
+            name: 'twitter:image',
+            content: frontmatter.thumbnail,
+          },
+          { name: 'twitter:title', content: frontmatter.title },
+          { name: 'twitter:description', content: frontmatter.description },
+          { name: 'twitter:card', content: 'summary_large_image' },
+          { name: 'twitter:site', content: '@alvarosabu' },
+          { name: 'twitter:creator', content: '@alvarosabu' },
+          { name: 'og:title', content: frontmatter.title },
+          { name: 'og:description', content: frontmatter.description },
+          { name: 'og:image', content: frontmatter.thumbnail },
+          { name: 'og:url', content: frontmatter.url },
+          { name: 'og:site_name', content: 'TresJS' },
+        ],
+      }}
+    />
+    <title>{frontmatter.title}</title>
+  </head>
+  <body>
+    <slot />
+    <style is:global>
+      :root {
+        --accent: 124, 58, 237;
+        --accent-gradient: linear-gradient(45deg, rgb(var(--accent)), #da62c4 30%, white 60%);
+      }
+      html {
+        font-family: system-ui, sans-serif;
+        background-color: #f6f6f6;
+      }
+      body {
+        margin: 0;
+      }
+      code {
+        font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono,
+          Courier New, monospace;
+      }
+    </style>
+  </body>
+</html>

+ 78 - 29
apps/playground/src/layouts/Layout.astro

@@ -1,38 +1,87 @@
 ---
+import { SEO } from 'astro-seo'
+
+import Header from '../components/Header.astro'
+
 export interface Props {
-	title: string;
+  title: string
 }
 
-const { title } = Astro.props;
+const { title } = Astro.props
+
+const meta = {
+  description: 'Playground for TresJS experiments for Vue',
+  thumbnail: 'https://pbs.twimg.com/media/FjtkgAlXwAIF7a_?format=png&name=4096x4096',
+  url: 'https://playground.tresjs.org/',
+}
 ---
 
 <!DOCTYPE html>
 <html lang="en">
-	<head>
-		<meta charset="UTF-8" />
-		<meta name="viewport" content="width=device-width" />
-		<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
-		<meta name="generator" content={Astro.generator} />
-		<title>{title}</title>
-	</head>
-	<body>
-		<slot />
-	</body>
+  <head>
+    <meta charset="UTF-8" />
+    <meta name="viewport" content="width=device-width" />
+    <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
+    <meta name="generator" content={Astro.generator} />
+    <title>{title}</title>
+    <SEO
+      title={title}
+      description={meta.description}
+      openGraph={{
+        basic: {
+          title: title,
+          type: 'website',
+          image: meta.thumbnail,
+        },
+        image: {
+          alt: 'TresJS',
+        },
+      }}
+      twitter={{
+        creator: '@alvarosabu',
+      }}
+      extend={{
+        // extending the default link tags
+        link: [{ rel: 'icon', href: '/favicon.ico' }],
+        // extending the default meta tags
+        meta: [
+          {
+            name: 'twitter:image',
+            content: meta.thumbnail,
+          },
+          { name: 'twitter:title', content: title },
+          { name: 'twitter:description', content: meta.description },
+          { name: 'twitter:card', content: 'summary_large_image' },
+          { name: 'twitter:site', content: '@alvarosabu' },
+          { name: 'twitter:creator', content: '@alvarosabu' },
+          { name: 'og:title', content: title },
+          { name: 'og:description', content: meta.description },
+          { name: 'og:image', content: meta.thumbnail },
+          { name: 'og:url', content: meta.url },
+          { name: 'og:site_name', content: 'TresJS' },
+        ],
+      }}
+    />
+  </head>
+  <body>
+    <Header title={title} visible={Astro.url.pathname === '/'} />
+    <slot />
+    <style is:global>
+      :root {
+        --accent: 124, 58, 237;
+        --accent-gradient: linear-gradient(45deg, rgb(var(--accent)), #da62c4 30%, white 60%);
+      }
+      html {
+        font-family: system-ui, sans-serif;
+        background-color: #f6f6f6;
+      }
+      body {
+        margin: 0;
+      }
+      code {
+        font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono,
+          Courier New, monospace;
+      }
+    </style>
+  </body>
 </html>
-<style is:global>
-	:root {
-		--accent: 124, 58, 237;
-		--accent-gradient: linear-gradient(45deg, rgb(var(--accent)), #da62c4 30%, white 60%);
-	}
-	html {
-		font-family: system-ui, sans-serif;
-		background-color: #F6F6F6;
-	}
-	body {
-		margin: 0;
-	}
-	code {
-		font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono,
-			Bitstream Vera Sans Mono, Courier New, monospace;
-	}
-</style>

+ 34 - 7
apps/playground/src/pages/index.astro

@@ -1,11 +1,38 @@
 ---
-import TheExperience from '../components/TheExperience.vue';
-import Layout from '../layouts/Layout.astro';
+import Layout from '../layouts/Layout.astro'
+
+const vueExperiments = await Astro.glob('./vue/**/*.mdx')
+const experiments = [...vueExperiments].map(experiment => ({
+  framework: 'vue',
+  ...experiment,
+}))
 ---
 
-<Layout title="Welcome to Astro.">
-	<main>
-		<TheExperience client:only />
-	</main>
+<Layout title="Playground">
+  <main
+    class="container px-4 py-20 sm:px-0 mx-auto grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-8 sm:gap-12 md:gap-16"
+  >
+    {
+      experiments.map(experiment => (
+        <a href={experiment.url} class="card bg-base-100  shadow-xl rounded-lg overflow-hidden relative">
+          <figure>
+            <img src={experiment.frontmatter.thumbnail} alt={experiment.frontmatter.title} />
+          </figure>
+          <div class="card-body p-4">
+            <h2 class="card-title font-bold mb-8 text-lg">{experiment.frontmatter.title}</h2>
+            <p class="mb-4">{experiment.frontmatter.description}</p>
+            <footer class="card-actions justify-end">
+              <ul class="flex flex-wrap">
+                {experiment.frontmatter.tags.map(tag => (
+                  <li>
+                    <span class="text-xs text-gray-700 font-semibold bg-lime-200 py-1 px-2 rounded mr-2">{tag}</span>
+                  </li>
+                ))}
+              </ul>
+            </footer>
+          </div>
+        </a>
+      ))
+    }
+  </main>
 </Layout>
-

+ 61 - 0
apps/playground/src/pages/vue/animations.mdx

@@ -0,0 +1,61 @@
+---
+layout: /@/layouts/ExperimentLayout.astro
+thumbnail: /animations.png
+title: Animations
+author: Alvarosabu
+description: A basic example of how to animate a geometry using useRendererLoop composable
+tags: ['basic', 'animations', 'useRendererLoop']
+---
+
+import BasicAnimations from '/@/components/BasicAnimations.vue'
+import TheInfo from '/@/components/TheInfo.astro'
+
+<BasicAnimations client:only />
+
+<TheInfo >
+# { frontmatter.title }
+
+Tutorial [here](https://tresjs.org/examples/basic-animations.html)
+
+```vue
+<script setup lang="ts">
+import { ShallowRef, shallowRef } from 'vue'
+
+import { useRenderLoop, TresInstance } from '@tresjs/core'
+import { OrbitControls } from '@tresjs/cientos'
+
+const boxRef: ShallowRef<TresInstance | null> = shallowRef(null)
+
+const { onLoop } = useRenderLoop()
+
+onLoop(({ delta, elapsed }) => {
+  if (boxRef.value) {
+    boxRef.value.rotation.y += delta
+    boxRef.value.rotation.z = elapsed * 0.2
+  }
+})
+</script>
+
+<template>
+  <TresCanvas
+    clear-color="#82DBC5"
+    shadows
+    alpha
+    window-size
+    power-preference="high-performance"
+    physically-correct-lights
+  >
+    <OrbitControls />
+    <TresPerspectiveCamera :position="[1, 2, 5]" :fov="45" :aspect="1" :near="0.1" :far="1000" />
+    <TresScene>
+      <TresMesh ref="boxRef" :scale="1" cast-shadow>
+        <TresBoxGeometry :args="[1, 1, 1]" />
+        <TresMeshNormalMaterial />
+      </TresMesh>
+      <TresDirectionalLight :position="[0, 2, 4]" :intensity="2" cast-shadow />
+    </TresScene>
+  </TresCanvas>
+</template>
+```
+
+</TheInfo>

+ 59 - 0
apps/playground/src/pages/vue/basic.mdx

@@ -0,0 +1,59 @@
+---
+layout: /@/layouts/ExperimentLayout.astro
+thumbnail: /tres-basic.png
+title: Tres Basic
+author: Alvarosabu
+description: A basic example of how to create a scene with TresJS
+tags: ['basic', 'orbit-controls']
+---
+
+import TresBasic from '/@/components/TresBasic.vue'
+import TheInfo from '/@/components/TheInfo.astro'
+
+<TresBasic client:only />
+
+<TheInfo >
+# { frontmatter.title }
+
+```vue
+<script setup lang="ts">
+import { reactive } from 'vue'
+import { BasicShadowMap, sRGBEncoding, NoToneMapping } from 'three'
+
+import { OrbitControls } from '@tresjs/cientos'
+
+const state = reactive({
+  clearColor: '#82DBC5',
+  shadows: true,
+  alpha: false,
+  physicallyCorrectLights: true,
+  shadowMapType: BasicShadowMap,
+  outputEncoding: sRGBEncoding,
+  toneMapping: NoToneMapping,
+})
+</script>
+
+<template>
+  <TresCanvas v-bind="state">
+    <OrbitControls />
+    <TresPerspectiveCamera :position="[11, 11, 11]" :fov="45" :aspect="1" :near="0.1" :far="1000" />
+    <TresScene>
+      <TresMesh :position="[-2, 2, 0]" :rotation="[0, Math.PI, 0]" cast-shadow>
+        <TresConeGeometry :args="[1, 1.5, 3]" />
+        <TresMeshToonMaterial color="#82DBC5" />
+      </TresMesh>
+      <TresMesh :position="[0, 0, 0]" cast-shadow>
+        <TresBoxGeometry :args="[1.5, 1.5, 1.5]" />
+        <TresMeshToonMaterial color="#4F4F4F" />
+      </TresMesh>
+      <TresMesh :position="[2, -2, 0]" cast-shadow>
+        <TresSphereGeometry />
+        <TresMeshToonMaterial color="#FBB03B" />
+      </TresMesh>
+      <TresDirectionalLight :position="[0, 2, 4]" :intensity="2" cast-shadow />
+    </TresScene>
+  </TresCanvas>
+</template>
+```
+
+</TheInfo>

+ 0 - 11
apps/playground/src/pages/vue/gltf-model.astro

@@ -1,11 +0,0 @@
----
-import GLTFModel from '/@/components/GLTFModel.vue';
-import Layout from '/@/layouts/Layout.astro';
----
-
-<Layout title="Welcome to Astro.">
-	<main>
-		<GLTFModel client:only />
-	</main>
-</Layout>
-

+ 40 - 0
apps/playground/src/pages/vue/gltf-model.mdx

@@ -0,0 +1,40 @@
+---
+layout: /@/layouts/ExperimentLayout.astro
+thumbnail: /gltf-model.png
+title: GLTF Model
+author: Alvarosabu
+description: How to add a Gltf Model to using GLTFModel component on TresJS
+tags: ['basic', 'cientos', 'gltf-model']
+---
+
+import GLTFModel from '/@/components/GLTFModel.vue'
+import TheInfo from '/@/components/TheInfo.astro'
+
+<GLTFModel client:only />
+
+<TheInfo >
+# { frontmatter.title }
+
+```vue
+<script setup lang="ts">
+import { sRGBEncoding } from 'three'
+
+import { OrbitControls, GLTFModel } from '@tresjs/cientos'
+</script>
+
+<template>
+  <Suspense>
+    <TresCanvas clear-color="#82DBC5" shadows alpha window-size :output-encoding="sRGBEncoding">
+      <OrbitControls />
+      <TresPerspectiveCamera :position="[5, 5, 5]" :fov="75" :near="0.1" :far="1000" />
+      <TresScene :fog="'#82DBC5'">
+        <TresAmbientLight :color="0xffffff" :intensity="0.25" />
+        <TresDirectionalLight :position="[0, 8, 4]" :intensity="0.7" cast-shadow />
+        <GLTFModel path="https://raw.githubusercontent.com/Tresjs/assets/main/models/gltf/aku-aku/AkuAku.gltf" draco />
+      </TresScene>
+    </TresCanvas>
+  </Suspense>
+</template>
+```
+
+</TheInfo>

+ 147 - 0
apps/playground/src/pages/vue/materials.mdx

@@ -0,0 +1,147 @@
+---
+layout: /@/layouts/ExperimentLayout.astro
+thumbnail: /materials.png
+title: Materials
+author: Alvarosabu
+description: A basic example of how to create a scene with TresJS
+tags: ['basic', 'materials', 'useTweakPane']
+---
+
+import Materials from '/@/components/Materials.vue'
+import TheInfo from '/@/components/TheInfo.astro'
+
+<Materials client:only />
+
+<TheInfo >
+# { frontmatter.title }
+
+```vue
+<script setup lang="ts">
+import { OrbitControls, Plane, useTweakPane } from '@tresjs/cientos'
+import {
+  BasicShadowMap,
+  Color,
+  CubeTextureLoader,
+  MeshBasicMaterial,
+  MeshLambertMaterial,
+  MeshMatcapMaterial,
+  MeshNormalMaterial,
+  MeshPhongMaterial,
+  MeshPhysicalMaterial,
+  MeshStandardMaterial,
+  MeshToonMaterial,
+  NoToneMapping,
+  sRGBEncoding,
+} from 'three'
+import { shallowReactive, shallowRef } from 'vue'
+
+const { pane } = useTweakPane()
+const state = shallowReactive({
+  clearColor: '#4f4f4f',
+  shadows: true,
+  alpha: false,
+  physicallyCorrectLights: true,
+  shadowMapType: BasicShadowMap,
+  outputEncoding: sRGBEncoding,
+  toneMapping: NoToneMapping,
+})
+
+const cubeTextureLoader = new CubeTextureLoader()
+
+const environmentMap = cubeTextureLoader.load([
+  'https://raw.githubusercontent.com/Tresjs/assets/main/textures/environmentMap/px.jpg',
+  'https://raw.githubusercontent.com/Tresjs/assets/main/textures/environmentMap/nx.jpg',
+  'https://raw.githubusercontent.com/Tresjs/assets/main/textures/environmentMap/py.jpg',
+  'https://raw.githubusercontent.com/Tresjs/assets/main/textures/environmentMap/ny.jpg',
+  'https://raw.githubusercontent.com/Tresjs/assets/main/textures/environmentMap/pz.jpg',
+  'https://raw.githubusercontent.com/Tresjs/assets/main/textures/environmentMap/nz.jpg',
+])
+
+const materialState = shallowReactive({
+  color: '#008080',
+  metalness: 0.5,
+  wireframe: false,
+})
+
+const sphereRef = shallowRef()
+pane
+  .addInput(materialState, 'color', {
+    label: 'Color',
+  })
+  .on('change', (ev: any) => {
+    sphereRef.value.material.color = new Color(ev.value)
+  })
+
+pane
+  .addInput(materialState, 'wireframe', {
+    label: 'Wireframe',
+  })
+  .on('change', (ev: any) => {
+    sphereRef.value.material.wireframe = ev.value
+  })
+
+const materialProps = ['metalness', 'roughness']
+
+materialProps.forEach(element => {
+  pane
+    .addBlade({
+      view: 'slider',
+      label: element,
+      min: 0,
+      max: 1,
+      value: 0.5,
+    })
+    .on('change', (ev: any) => {
+      materialState[element] = ev.value
+      sphereRef.value.material[element] = ev.value
+    })
+})
+
+pane
+  .addBlade({
+    view: 'list',
+    label: 'Materials',
+    options: [
+      { text: 'MeshBasicMaterial', value: MeshBasicMaterial },
+      { text: 'MeshToonMaterial', value: MeshToonMaterial },
+      /*    { text: 'MeshDepthMaterial', value: MeshDepthMaterial },
+      { text: 'MeshDistanceMaterial', value: MeshDistanceMaterial }, */
+      { text: 'MeshLambertMaterial', value: MeshLambertMaterial },
+      { text: 'MeshMatcapMaterial', value: MeshMatcapMaterial },
+      { text: 'MeshNormalMaterial', value: MeshNormalMaterial },
+      { text: 'MeshPhongMaterial', value: MeshPhongMaterial },
+      { text: 'MeshPhysicalMaterial', value: MeshPhysicalMaterial },
+      { text: 'MeshStandardMaterial', value: MeshStandardMaterial },
+    ],
+    value: MeshToonMaterial,
+  })
+  .on('change', ev => {
+    sphereRef.value.material = new ev.value(materialState)
+
+    if (ev.value === MeshStandardMaterial || ev.value === MeshPhysicalMaterial) {
+      sphereRef.value.material.envMap = environmentMap
+    }
+  })
+</script>
+<template>
+  <TresCanvas v-bind="state">
+    <TresPerspectiveCamera :position="[3, 3, 5]" :fov="45" :aspect="1" :near="0.1" :far="1000" />
+    <OrbitControls />
+    <TresScene>
+      <TresMesh ref="sphereRef" :position="[0, 1, 0]" cast-shadow recieve-shadow>
+        <TresSphereGeometry :args="[1, 32, 32]" />
+        <TresMeshToonMaterial :color="materialState.color" />
+      </TresMesh>
+      <Plane :args="[10, 10]" recieve-shadow>
+        <TresMeshToonMaterial color="#222" />
+      </Plane>
+      <TresDirectionalLight :position="[-3, 4, 4]" :intensity="2" cast-shadow />
+      <TresDirectionalLight :position="[3, 4, 0]" :intensity="0.5" cast-shadow />
+
+      <TresAmbientLight :intensity="1" />
+    </TresScene>
+  </TresCanvas>
+</template>
+```
+
+</TheInfo>

+ 334 - 0
apps/playground/src/pages/vue/portal-journey.mdx

@@ -0,0 +1,334 @@
+---
+layout: /@/layouts/ExperimentLayout.astro
+thumbnail: /portal-journey.png
+title: Portal Journey
+author: Alvarosabu
+description: A basic example of how to create a scene with TresJS
+tags: ['gltf', 'shaders', 'useTexture', 'useGLTF', 'useTweakPane', 'baked']
+---
+
+import TheExperience from '/@/components/portal-journey/TheExperience.vue'
+import TheInfo from '/@/components/TheInfo.astro'
+
+<TheExperience client:only />
+
+<TheInfo >
+# { frontmatter.title }
+
+Famous portal scene from the amazing [Three.js Journey](https://threejs-journey.com/) course by [Bruno Simon](https://bruno-simon.com/)
+
+```vue
+<script setup lang="ts">
+import { OrbitControls } from '@tresjs/cientos'
+import ThePortal from './ThePortal.vue'
+import TheFireFlies from './TheFireFlies.vue'
+</script>
+
+<template>
+  <Suspense>
+    <TresCanvas clear-color="#201919" shadows alpha window-size power-preference="high-performance">
+      <OrbitControls />
+      <TresPerspectiveCamera :position="[5, 5, 5]" :fov="45" :aspect="1" :near="0.1" :far="1000" />
+      <TresScene>
+        <TresFog :args="['#201919', 0.1, 75]" />
+        <ThePortal />
+        <TheFireFlies />
+        <TresAmbientLight :position="[10, 10, 10]" :intensity="1.5" color="#00ff00" />
+      </TresScene>
+    </TresCanvas>
+  </Suspense>
+</template>
+```
+
+## ThePortal.vue
+
+```vue
+<script setup lang="ts">
+import { sRGBEncoding, DoubleSide, MeshBasicMaterial, ShaderMaterial, Color, Mesh } from 'three'
+import { useRenderLoop, useTexture } from '@tresjs/core'
+import { useGLTF, useTweakPane } from '@tresjs/cientos'
+
+import PortalVertex from './shaders/portal/vertex.glsl'
+import PortalFragment from './shaders/portal/fragment.glsl'
+
+const experiment = {
+  portalColorStart: '#7030eb',
+  portalColorEnd: '#ddc0ff',
+}
+
+const { pane } = useTweakPane()
+
+const portalCtrls = pane.addFolder({ title: 'Portal' })
+portalCtrls
+  .addInput(experiment, 'portalColorStart', {
+    label: 'color start',
+    min: 0,
+    max: 1,
+    step: 0.01,
+  })
+  .on('change', ({ value }) => {
+    portalLightMaterial.uniforms.uColorStart.value.set(value)
+  })
+portalCtrls
+  .addInput(experiment, 'portalColorEnd', {
+    label: 'color end',
+    min: 0,
+    max: 1,
+    step: 0.01,
+  })
+  .on('change', ({ value }) => {
+    portalLightMaterial.uniforms.uColorEnd.value.set(value)
+  })
+
+const { scene: portal } = await useGLTF(
+  'https://raw.githubusercontent.com/Tresjs/assets/main/models/gltf/portal/portal.glb',
+  {
+    draco: true,
+  },
+)
+
+const bakedTexture = await useTexture([
+  'https://raw.githubusercontent.com/Tresjs/assets/main/models/gltf/portal/baked.jpg',
+])
+
+bakedTexture.flipY = false
+bakedTexture.encoding = sRGBEncoding
+
+// Baked material
+const bakedMaterial = new MeshBasicMaterial({
+  map: bakedTexture,
+  side: DoubleSide,
+})
+
+const portalLightMaterial = new ShaderMaterial({
+  uniforms: {
+    uTime: { value: 0 },
+    uColorStart: { value: new Color(experiment.portalColorStart) },
+    uColorEnd: { value: new Color(experiment.portalColorEnd) },
+  },
+  vertexShader: PortalVertex,
+  fragmentShader: PortalFragment,
+  side: DoubleSide,
+})
+
+const portalObj = portal
+const bakedMesh = portalObj.children.find(child => child.name === 'baked')
+;(bakedMesh as Mesh).material = bakedMaterial
+const portalCircle = portalObj.children.find(child => child.name === 'portalCircle')
+;(portalCircle as Mesh).material = portalLightMaterial
+
+const { onLoop } = useRenderLoop()
+
+onLoop(({ _delta, elapsed }) => {
+  portalLightMaterial.uniforms.uTime.value = elapsed
+})
+</script>
+<template>
+  <TresMesh v-bind="portal" />
+</template>
+```
+
+### Shaders
+
+```glsl
+// portal/vertex.glsl
+varying vec2 vUv;
+
+void main()
+{
+    vec4 modelPosition = modelMatrix * vec4(position, 1.0);
+    vec4 viewPosition = viewMatrix * modelPosition;
+    vec4 projectionPosition = projectionMatrix * viewPosition;
+
+    gl_Position = projectionPosition;
+    vUv = uv;
+}
+```
+
+```glsl
+// portal/fragment.glsl
+varying vec2 vUv;
+uniform float uTime;
+uniform vec3 uColorStart;
+uniform vec3 uColorEnd;
+
+//	Classic Perlin 3D Noise
+//	by Stefan Gustavson
+//
+vec4 permute(vec4 x){return mod(((x*34.0)+1.0)*x, 289.0);}
+vec4 taylorInvSqrt(vec4 r){return 1.79284291400159 - 0.85373472095314 * r;}
+vec3 fade(vec3 t) {return t*t*t*(t*(t*6.0-15.0)+10.0);}
+
+float cnoise(vec3 P){
+vec3 Pi0 = floor(P); // Integer part for indexing
+vec3 Pi1 = Pi0 + vec3(1.0); // Integer part + 1
+Pi0 = mod(Pi0, 289.0);
+Pi1 = mod(Pi1, 289.0);
+vec3 Pf0 = fract(P); // Fractional part for interpolation
+vec3 Pf1 = Pf0 - vec3(1.0); // Fractional part - 1.0
+vec4 ix = vec4(Pi0.x, Pi1.x, Pi0.x, Pi1.x);
+vec4 iy = vec4(Pi0.yy, Pi1.yy);
+vec4 iz0 = Pi0.zzzz;
+vec4 iz1 = Pi1.zzzz;
+
+vec4 ixy = permute(permute(ix) + iy);
+vec4 ixy0 = permute(ixy + iz0);
+vec4 ixy1 = permute(ixy + iz1);
+
+vec4 gx0 = ixy0 / 7.0;
+vec4 gy0 = fract(floor(gx0) / 7.0) - 0.5;
+gx0 = fract(gx0);
+vec4 gz0 = vec4(0.5) - abs(gx0) - abs(gy0);
+vec4 sz0 = step(gz0, vec4(0.0));
+gx0 -= sz0 * (step(0.0, gx0) - 0.5);
+gy0 -= sz0 * (step(0.0, gy0) - 0.5);
+
+vec4 gx1 = ixy1 / 7.0;
+vec4 gy1 = fract(floor(gx1) / 7.0) - 0.5;
+gx1 = fract(gx1);
+vec4 gz1 = vec4(0.5) - abs(gx1) - abs(gy1);
+vec4 sz1 = step(gz1, vec4(0.0));
+gx1 -= sz1 * (step(0.0, gx1) - 0.5);
+gy1 -= sz1 * (step(0.0, gy1) - 0.5);
+
+vec3 g000 = vec3(gx0.x,gy0.x,gz0.x);
+vec3 g100 = vec3(gx0.y,gy0.y,gz0.y);
+vec3 g010 = vec3(gx0.z,gy0.z,gz0.z);
+vec3 g110 = vec3(gx0.w,gy0.w,gz0.w);
+vec3 g001 = vec3(gx1.x,gy1.x,gz1.x);
+vec3 g101 = vec3(gx1.y,gy1.y,gz1.y);
+vec3 g011 = vec3(gx1.z,gy1.z,gz1.z);
+vec3 g111 = vec3(gx1.w,gy1.w,gz1.w);
+
+vec4 norm0 = taylorInvSqrt(vec4(dot(g000, g000), dot(g010, g010), dot(g100, g100), dot(g110, g110)));
+g000 *= norm0.x;
+g010 *= norm0.y;
+g100 *= norm0.z;
+g110 *= norm0.w;
+vec4 norm1 = taylorInvSqrt(vec4(dot(g001, g001), dot(g011, g011), dot(g101, g101), dot(g111, g111)));
+g001 *= norm1.x;
+g011 *= norm1.y;
+g101 *= norm1.z;
+g111 *= norm1.w;
+
+float n000 = dot(g000, Pf0);
+float n100 = dot(g100, vec3(Pf1.x, Pf0.yz));
+float n010 = dot(g010, vec3(Pf0.x, Pf1.y, Pf0.z));
+float n110 = dot(g110, vec3(Pf1.xy, Pf0.z));
+float n001 = dot(g001, vec3(Pf0.xy, Pf1.z));
+float n101 = dot(g101, vec3(Pf1.x, Pf0.y, Pf1.z));
+float n011 = dot(g011, vec3(Pf0.x, Pf1.yz));
+float n111 = dot(g111, Pf1);
+
+vec3 fade_xyz = fade(Pf0);
+vec4 n_z = mix(vec4(n000, n100, n010, n110), vec4(n001, n101, n011, n111), fade_xyz.z);
+vec2 n_yz = mix(n_z.xy, n_z.zw, fade_xyz.y);
+float n_xyz = mix(n_yz.x, n_yz.y, fade_xyz.x);
+return 2.2 * n_xyz;
+}
+
+void main()
+{
+  float speed = 0.1;
+  // Displace the UV coordinates by a noise value
+  vec2 displacedUv = vUv + cnoise(vec3(vUv* 5.0, uTime * speed));
+  // Get the color from the texture
+  float strength = cnoise(vec3(displacedUv * 5.0, uTime * speed * 2.0));
+
+  // Outer Glow
+
+  float outerGlow = distance(vUv, vec2(0.5)) * 5.0 - 1.4;
+  strength += outerGlow;
+
+  strength += step(- 0.2, strength) * 0.8;
+
+  strength = clamp(strength, 0.0, 1.0);
+
+  vec3 color = mix(uColorStart, uColorEnd, strength);
+
+  gl_FragColor = vec4(color, 1.0);
+}
+```
+
+## TheFireFlies.vue
+
+```vue
+<script setup lang="ts">
+import { useRenderLoop } from '@tresjs/core'
+import { AdditiveBlending } from 'three'
+import FirefliesVertex from './shaders/fireflies/vertex.glsl'
+import FirefliesFragment from './shaders/fireflies/fragment.glsl'
+
+const shader = {
+  transparent: true,
+  blending: AdditiveBlending,
+  depthWrite: false,
+
+  vertexShader: FirefliesVertex,
+  fragmentShader: FirefliesFragment,
+  uniforms: {
+    uSize: { value: 100 },
+    uPixelRatio: { value: Math.min(window.devicePixelRatio, 2) },
+    uTime: { value: 0 },
+  },
+}
+
+const firefliesCount = 60
+const positionArray = new Float32Array(firefliesCount * 3)
+const scaleArray = new Float32Array(firefliesCount)
+
+for (let i = 0; i < firefliesCount; i++) {
+  positionArray[i * 3 + 0] = (Math.random() - 0.5) * 4
+  positionArray[i * 3 + 1] = Math.random() * 4
+  positionArray[i * 3 + 2] = (Math.random() - 0.5) * 4
+  scaleArray[i] = Math.random()
+}
+
+const { onLoop } = useRenderLoop()
+
+onLoop(({ elapsed }) => {
+  shader.uniforms.uTime.value = elapsed
+})
+</script>
+<template>
+  <TresPoints>
+    <TresBufferGeometry :position="[positionArray, 3]" :a-scale="[scaleArray, 1]" />
+    <TresShaderMaterial v-bind="shader" />
+  </TresPoints>
+</template>
+```
+
+### Shaders
+
+```glsl
+// fireflies/vertex.glsl
+uniform float uPixelRatio;
+uniform float uSize;
+uniform float uTime;
+attribute float aScale;
+
+void main()
+{
+    vec4 modelPosition = modelMatrix * vec4(position, 1.0);
+    modelPosition.y += sin(uTime + modelPosition.x * 100.0) * aScale * 0.2;
+    vec4 viewPosition = viewMatrix * modelPosition;
+    vec4 projectionPosition = projectionMatrix * viewPosition;
+
+    gl_Position = projectionPosition;
+    gl_PointSize = aScale * uSize * uPixelRatio;
+    gl_PointSize *= (1.0 / - viewPosition.z);
+}
+```
+
+```glsl
+// fireflies/fragment.glsl
+void main()
+{
+  float distanceToCenter = distance(gl_PointCoord, vec2(0.5));
+  float strength = 0.05 / distanceToCenter - 0.1;
+
+  gl_FragColor = vec4(1.0, 1.0, 1.0, strength);
+}
+```
+
+</TheInfo>

+ 85 - 0
apps/playground/src/pages/vue/textures.mdx

@@ -0,0 +1,85 @@
+---
+layout: /@/layouts/ExperimentLayout.astro
+thumbnail: /textures.png
+title: Textures
+author: Alvarosabu
+description: A basic example of how to load textures using the useTexture composables and suspense
+tags: ['basic', 'useTexture', 'suspense']
+---
+
+import Textures from '/@/components/textures/Textures.vue'
+import TheInfo from '/@/components/TheInfo.astro'
+
+<Textures client:only />
+
+<TheInfo >
+# { frontmatter.title }
+
+Tutorial available [here](https://tresjs.org/examples/load-textures.html)
+
+```vue
+<script setup lang="ts">
+import { Ref, ref } from 'vue'
+
+import { useTexture, useRenderLoop } from '@tresjs/core'
+import { OrbitControls, Plane } from '@tresjs/cientos'
+import { TresInstance } from '@tresjs/core/dist/types'
+
+const pbrTexture = await useTexture({
+  map: 'https://raw.githubusercontent.com/Tresjs/assets/main/textures/black-rock/Rock035_2K_Displacement.jpg',
+  displacementMap:
+    'https://raw.githubusercontent.com/Tresjs/assets/main/textures/black-rock/Rock035_2K_Displacement.jpg',
+  roughnessMap: 'https://raw.githubusercontent.com/Tresjs/assets/main/textures/black-rock/Rock035_2K_Roughness.jpg',
+  normalMap: 'https://raw.githubusercontent.com/Tresjs/assets/main/textures/black-rock/Rock035_2K_NormalGL.jpg',
+  ambientOcclusion:
+    'https://raw.githubusercontent.com/Tresjs/assets/main/textures/black-rock/Rock035_2K_AmbientOcclusion.jpg',
+})
+
+const blackRock = await useTexture({
+  map: 'https://raw.githubusercontent.com/Tresjs/assets/main/textures/black-rock/Rock035_2K_Color.jpg',
+  displacementMap:
+    'https://raw.githubusercontent.com/Tresjs/assets/main/textures/black-rock/Rock035_2K_Displacement.jpg',
+  roughnessMap: 'https://raw.githubusercontent.com/Tresjs/assets/main/textures/black-rock/Rock035_2K_Roughness.jpg',
+  normalMap: 'https://raw.githubusercontent.com/Tresjs/assets/main/textures/black-rock/Rock035_2K_NormalGL.jpg',
+  ambientOcclusion:
+    'https://raw.githubusercontent.com/Tresjs/assets/main/textures/black-rock/Rock035_2K_AmbientOcclusion.jpg',
+})
+
+const sphereRef: Ref<TresInstance | null> = ref(null)
+
+const { onLoop } = useRenderLoop()
+
+onLoop(({ delta }) => {
+  // I will run at every frame ~ 60FPS (depending of your monitor)
+  if (sphereRef.value) {
+    sphereRef.value.rotation.y += delta
+  }
+})
+</script>
+
+<template>
+  <TresCanvas
+    clear-color="#82DBC5"
+    shadows
+    alpha
+    window-size
+    power-preference="high-performance"
+    preserve-drawing-buffer
+  >
+    <OrbitControls />
+    <TresPerspectiveCamera :position="[11, 11, 11]" :fov="45" :aspect="1" :near="0.1" :far="1000" />
+    <TresScene>
+      <TresMesh ref="sphereRef" :position="[0, 4, 0]" :scale="1" cast-shadow>
+        <TresSphereGeometry :args="[1, 500, 500]" />
+        <TresMeshStandardMaterial v-bind="blackRock" displacement-scale="0.2" />
+      </TresMesh>
+      <Plane :args="[10, 10, 500, 500]">
+        <TresMeshStandardMaterial v-bind="pbrTexture" displacement-scale="0.6" />
+      </Plane>
+      <TresDirectionalLight :position="[0, 2, 4]" :intensity="1" cast-shadow />
+    </TresScene>
+  </TresCanvas>
+</template>
+```
+
+</TheInfo>

+ 0 - 11
apps/playground/src/pages/vue/transform-controls.astro

@@ -1,11 +0,0 @@
----
-import TransformControls from '/@/components/TransformControls.vue';
-import Layout from '/@/layouts/Layout.astro';
----
-
-<Layout title="Transform Controls.">
-	<main>
-		<TransformControls client:only />
-	</main>
-</Layout>
-

+ 111 - 0
apps/playground/src/pages/vue/transform-controls.mdx

@@ -0,0 +1,111 @@
+---
+layout: /@/layouts/ExperimentLayout.astro
+thumbnail: /transform-controls.png
+title: GLTF Model
+author: Alvarosabu
+description: Example of how to use Transform controls from cientos package
+tags: ['basic', 'cientos', 'use-tweak-pane', 'transform-controls']
+---
+
+import TransformControls from '/@/components/TransformControls.vue'
+import TheInfo from '/@/components/TheInfo.astro'
+
+<TransformControls client:only />
+
+<TheInfo >
+# { frontmatter.title }
+
+```vue
+<script setup lang="ts">
+import { shallowRef, shallowReactive } from 'vue'
+import { BasicShadowMap, sRGBEncoding, NoToneMapping } from 'three'
+
+import { OrbitControls, useTweakPane, TransformControls } from '@tresjs/cientos'
+
+const state = shallowReactive({
+  clearColor: '#201919',
+  shadows: true,
+  alpha: false,
+  physicallyCorrectLights: true,
+  shadowMapType: BasicShadowMap,
+  outputEncoding: sRGBEncoding,
+  toneMapping: NoToneMapping,
+})
+
+const transformState = shallowReactive({
+  mode: 'translate',
+  size: 1,
+  axis: 'XY',
+  showX: true,
+  showY: true,
+  showZ: true,
+})
+
+const boxRef = shallowRef()
+
+const { pane } = useTweakPane()
+
+pane
+  .addBlade({
+    view: 'list',
+    label: 'outputEncoding',
+    options: [
+      { text: 'Translate', value: 'translate' },
+      { text: 'Rotate', value: 'rotate' },
+      { text: 'Scale', value: 'scale' },
+    ],
+    value: transformState.mode,
+  })
+  .on('change', ev => {
+    transformState.mode = ev.value
+  })
+
+pane.addInput(transformState, 'size')
+
+const axisFolder = pane.addFolder({ title: 'Axis' })
+
+axisFolder
+  .addBlade({
+    view: 'list',
+    label: 'axis',
+    options: [
+      { text: 'X', value: 'X' },
+      { text: 'Y', value: 'Y' },
+      { text: 'XY', value: 'XY' },
+      { text: 'YZ', value: 'YZ' },
+      { text: 'XZ', value: 'XZ' },
+      { text: 'XYZ', value: 'XYZ' },
+    ],
+    value: transformState.axis,
+  })
+  .on('change', ev => {
+    transformState.axis = ev.value
+  })
+axisFolder.addInput(transformState, 'showX')
+axisFolder.addInput(transformState, 'showY')
+axisFolder.addInput(transformState, 'showZ')
+</script>
+
+<template>
+  <TresCanvas v-bind="state">
+    <OrbitControls make-default />
+    <TresPerspectiveCamera :position="[11, 11, 11]" :fov="45" :near="0.1" :far="1000" :look-at="[-8, 3, -3]" />
+
+    <TresScene>
+      <TransformControls :object="boxRef" v-bind="transformState" />
+      <TresMesh ref="boxRef" :position="[0, 4, 0]" cast-shadow>
+        <TresBoxGeometry :args="[1.5, 1.5, 1.5]" />
+        <TresMeshToonMaterial color="#FBB03B" />
+      </TresMesh>
+      <TresMesh :rotation="[-Math.PI / 2, 0, 0]" receive-shadow>
+        <TresPlaneGeometry :args="[10, 10, 10, 10]" />
+        <TresMeshToonMaterial />
+      </TresMesh>
+      <TresAmbientLight :intensity="0.5" />
+      <TresDirectionalLight :position="[0, 8, 4]" :intensity="1.5" cast-shadow />
+    </TresScene>
+  </TresCanvas>
+</template>
+```
+
+</TheInfo>

+ 0 - 11
apps/playground/src/pages/vue/tres-basic.astro

@@ -1,11 +0,0 @@
----
-import TresBasic from '/@/components/TresBasic.vue';
-import Layout from '/@/layouts/Layout.astro';
----
-
-<Layout title="Tres Basic">
-	<main>
-		<TresBasic client:only />
-	</main>
-</Layout>
-

+ 0 - 11
apps/playground/src/pages/vue/tres-donut.astro

@@ -1,11 +0,0 @@
----
-import TresDonut from '/@/components/TresDonut.vue';
-import Layout from '/@/layouts/Layout.astro';
----
-
-<Layout title="Tres Donut 🍩">
-	<main>
-		<TresDonut client:only />
-	</main>
-</Layout>
-

+ 41 - 0
apps/playground/src/pages/vue/tres-donut.mdx

@@ -0,0 +1,41 @@
+---
+layout: /@/layouts/ExperimentLayout.astro
+thumbnail: /tres-donut.png
+title: Tres Donut 🍩
+author: Alvarosabu
+description: Plain donut with TresJS
+tags: ['basic']
+---
+
+import TresDonut from '/@/components/TresDonut.vue'
+import TheInfo from '/@/components/TheInfo.astro'
+
+<TresDonut client:only />
+
+<TheInfo>
+# { frontmatter.title }
+
+```vue
+<script setup lang="ts">
+import { reactive } from 'vue'
+
+const state = reactive({
+  shadows: true,
+  alpha: false,
+})
+</script>
+
+<template>
+  <TresCanvas v-bind="state">
+    <TresPerspectiveCamera :position="[0, 0, 6]" :fov="75" :aspect="1" :near="0.1" :far="1000" />
+    <TresScene>
+      <TresMesh>
+        <TresTorusGeometry :args="[1, 0.5, 16, 32]" />
+        <TresMeshBasicMaterial color="orange" />
+      </TresMesh>
+    </TresScene>
+  </TresCanvas>
+</template>
+```
+
+</TheInfo>

+ 326 - 1
pnpm-lock.yaml

@@ -47,20 +47,36 @@ importers:
 
   apps/playground:
     specifiers:
+      '@astrojs/mdx': ^0.14.0
       '@astrojs/vue': ^1.2.2
+      '@iconify-json/carbon': ^1.1.13
+      '@iconify-json/logos': ^1.1.22
+      '@kidonng/daisyui': ^2.31.0
       '@tresjs/cientos': workspace:^1.4.0
       '@tresjs/core': workspace:^1.5.0
       astro: ^1.9.2
+      astro-seo: ^0.7.0
       three: ^0.148.0
+      unocss: ^0.48.0
+      unocss-preset-daisy: ^1.2.0
+      vite-plugin-glsl: ^1.0.1
       vue: ^3.2.45
     dependencies:
+      '@astrojs/mdx': 0.14.0
       '@astrojs/vue': 1.2.2_vue@3.2.45
       astro: 1.9.2
+      astro-seo: 0.7.0
       vue: 3.2.45
     devDependencies:
+      '@iconify-json/carbon': 1.1.13
+      '@iconify-json/logos': 1.1.22
+      '@kidonng/daisyui': 2.31.0
       '@tresjs/cientos': link:../../packages/cientos
       '@tresjs/core': link:../../packages/tres
       three: 0.148.0
+      unocss: 0.48.0
+      unocss-preset-daisy: 1.2.0_77u2kep7hemix4zf3mpsyjlcju
+      vite-plugin-glsl: 1.0.1
 
   packages/cientos:
     specifiers:
@@ -345,6 +361,32 @@ packages:
       - supports-color
     dev: false
 
+  /@astrojs/mdx/0.14.0:
+    resolution: {integrity: sha512-lmNh/7CeQmdZ0OCbnDnoDxQTKWleFdlT5YkjsutGIOhabY0xgCcWwb1Rbs/9m4vvTdCkp9zsZdRzUKEPFPbcsA==}
+    engines: {node: ^14.18.0 || >=16.12.0}
+    dependencies:
+      '@astrojs/markdown-remark': 1.2.0
+      '@astrojs/prism': 1.0.2
+      '@mdx-js/mdx': 2.2.1
+      '@mdx-js/rollup': 2.2.1
+      acorn: 8.8.1
+      es-module-lexer: 0.10.5
+      estree-util-visit: 1.2.0
+      github-slugger: 1.5.0
+      gray-matter: 4.0.3
+      kleur: 4.1.5
+      rehype-raw: 6.1.1
+      remark-frontmatter: 4.0.1
+      remark-gfm: 3.0.1
+      remark-smartypants: 2.0.0
+      shiki: 0.11.1
+      unist-util-visit: 4.1.1
+      vfile: 5.3.6
+    transitivePeerDependencies:
+      - rollup
+      - supports-color
+    dev: false
+
   /@astrojs/micromark-extension-mdx-jsx/1.0.3:
     resolution: {integrity: sha512-O15+i2DGG0qb1R/1SYbFXgOKDGbYdV8iJMtuboVb1S9YFQfMOJxaCMco0bhXQI7PmZcQ4pZWIjT5oZ64dXUtRA==}
     dependencies:
@@ -1306,6 +1348,18 @@ packages:
     resolution: {integrity: sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==}
     dev: true
 
+  /@iconify-json/carbon/1.1.13:
+    resolution: {integrity: sha512-qPR7n3JkCqIrvjxnyUPIejhn0wrZJsLmija59U/zwFm5SMOITCfLx+Jp6VecnL0Sm76zRE5Kv54VzolQljB97A==}
+    dependencies:
+      '@iconify/types': 2.0.0
+    dev: true
+
+  /@iconify-json/logos/1.1.22:
+    resolution: {integrity: sha512-vlkTWWWzQ9eghWaoq2D51jPDJBhn6yvjr4TvRJxVPisIm0yDkvt2l4yq/QPonZBSaKuEXga5omDulJHIcSVR3A==}
+    dependencies:
+      '@iconify/types': 2.0.0
+    dev: true
+
   /@iconify/types/2.0.0:
     resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==}
     dev: true
@@ -1360,6 +1414,10 @@ packages:
       '@jridgewell/resolve-uri': 3.1.0
       '@jridgewell/sourcemap-codec': 1.4.14
 
+  /@kidonng/daisyui/2.31.0:
+    resolution: {integrity: sha512-cwIwgYOFF2KPPx0xyUycmYCk1iReMm/3inWXSS7CzSDWSni0ZvxJAaHm9Cb5xElrRRx/pKDTGNJR5imRfO6PLA==}
+    dev: true
+
   /@ljharb/has-package-exports-patterns/0.0.2:
     resolution: {integrity: sha512-4/RWEeXDO6bocPONheFe6gX/oQdP/bEpv0oL4HqjPP5DCenBSt0mHgahppY49N0CpsaqffdwPq+TlX9CYOq2Dw==}
     dev: false
@@ -1384,6 +1442,43 @@ packages:
       read-yaml-file: 1.1.0
     dev: true
 
+  /@mdx-js/mdx/2.2.1:
+    resolution: {integrity: sha512-hZ3ex7exYLJn6FfReq8yTvA6TE53uW9UHJQM9IlSauOuS55J9y8RtA7W+dzp6Yrzr00/U1sd7q+Wf61q6SfiTQ==}
+    dependencies:
+      '@types/estree-jsx': 1.0.0
+      '@types/mdx': 2.0.3
+      estree-util-build-jsx: 2.2.2
+      estree-util-is-identifier-name: 2.0.1
+      estree-util-to-js: 1.1.0
+      estree-walker: 3.0.2
+      hast-util-to-estree: 2.2.1
+      markdown-extensions: 1.1.1
+      periscopic: 3.0.4
+      remark-mdx: 2.2.1
+      remark-parse: 10.0.1
+      remark-rehype: 10.1.0
+      unified: 10.1.2
+      unist-util-position-from-estree: 1.1.1
+      unist-util-stringify-position: 3.0.2
+      unist-util-visit: 4.1.1
+      vfile: 5.3.6
+    transitivePeerDependencies:
+      - supports-color
+    dev: false
+
+  /@mdx-js/rollup/2.2.1:
+    resolution: {integrity: sha512-wpGeK9iO7gPEIyC/ZTiggLY/MkEWDj5IWSsjlpkefgjb5RbmUukXU6/D2rHA+VAopxigS3NlaIL2ctpYBi4fmg==}
+    peerDependencies:
+      rollup: '>=2'
+    dependencies:
+      '@mdx-js/mdx': 2.2.1
+      '@rollup/pluginutils': 5.0.2
+      source-map: 0.7.4
+      vfile: 5.3.6
+    transitivePeerDependencies:
+      - supports-color
+    dev: false
+
   /@microsoft/api-extractor-model/7.25.2:
     resolution: {integrity: sha512-+h1uCrLQXFAKMUdghhdDcnniDB+6UA/lS9ArlB4QZQ34UbLuXNy2oQ6fafFK8cKXU4mUPTF/yGRjv7JKD5L7eg==}
     dependencies:
@@ -1632,7 +1727,6 @@ packages:
       '@types/estree': 1.0.0
       estree-walker: 2.0.2
       picomatch: 2.3.1
-    dev: true
 
   /@rushstack/node-core-library/3.53.2:
     resolution: {integrity: sha512-FggLe5DQs0X9MNFeJN3/EXwb+8hyZUTEp2i+V1e8r4Va4JgkjBNY0BuEaQI+3DW6S4apV3UtXU3im17MSY00DA==}
@@ -1819,6 +1913,10 @@ packages:
       '@types/unist': 2.0.6
     dev: false
 
+  /@types/mdx/2.0.3:
+    resolution: {integrity: sha512-IgHxcT3RC8LzFLhKwP3gbMPeaK7BM9eBH46OdapPA7yvuIUJ8H6zHZV53J8hGZcTSnt95jANt+rTBNUUc22ACQ==}
+    dev: false
+
   /@types/minimist/1.2.2:
     resolution: {integrity: sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==}
     dev: true
@@ -2621,6 +2719,15 @@ packages:
       tslib: 2.4.1
     dev: false
 
+  /astring/1.8.4:
+    resolution: {integrity: sha512-97a+l2LBU3Op3bBQEff79i/E4jMD2ZLFD8rHx9B6mXyB2uQwhJQYfiDqUwtfjF4QA1F2qs//N6Cw8LetMbQjcw==}
+    hasBin: true
+    dev: false
+
+  /astro-seo/0.7.0:
+    resolution: {integrity: sha512-G7zJUr4lfKLeqfWx2g5rfuBsOsIOfqxIOqErQfrMsMchDFfLFxNKAuW8yAo8hynJJwBvtGyS/vOXgGdMVVCFrA==}
+    dev: false
+
   /astro/1.9.2:
     resolution: {integrity: sha512-L+Ma0eR0Aa6QZg7RF0lEs+106Ye1/zukvtq3KtsYIogAojltlwllwU9X5CwMBzFwA55NxpNp4gSRh5US/xb+8Q==}
     engines: {node: ^14.18.0 || >=16.12.0, npm: '>=6.14.0'}
@@ -3857,6 +3964,10 @@ packages:
       isarray: 2.0.5
     dev: true
 
+  /es-module-lexer/0.10.5:
+    resolution: {integrity: sha512-+7IwY/kiGAacQfY+YBhKMvEmyAJnw5grTUgjG85Pe7vcUI/6b7pZjZG8nQ7+48YhzEAEqrEgD2dCz/JIK+AYvw==}
+    dev: false
+
   /es-module-lexer/1.1.0:
     resolution: {integrity: sha512-fJg+1tiyEeS8figV+fPcPpm8WqJEflG3yPU0NOm5xMvrNkuiy7HzX/Ljng4Y0hAoiw4/3hQTCFYw+ub8+a2pRA==}
     dev: false
@@ -4303,10 +4414,32 @@ packages:
     engines: {node: '>=4.0'}
     dev: true
 
+  /estree-util-attach-comments/2.1.0:
+    resolution: {integrity: sha512-rJz6I4L0GaXYtHpoMScgDIwM0/Vwbu5shbMeER596rB2D1EWF6+Gj0e0UKzJPZrpoOc87+Q2kgVFHfjAymIqmw==}
+    dependencies:
+      '@types/estree': 1.0.0
+    dev: false
+
+  /estree-util-build-jsx/2.2.2:
+    resolution: {integrity: sha512-m56vOXcOBuaF+Igpb9OPAy7f9w9OIkb5yhjsZuaPm7HoGi4oTOQi0h2+yZ+AtKklYFZ+rPC4n0wYCJCEU1ONqg==}
+    dependencies:
+      '@types/estree-jsx': 1.0.0
+      estree-util-is-identifier-name: 2.0.1
+      estree-walker: 3.0.2
+    dev: false
+
   /estree-util-is-identifier-name/2.0.1:
     resolution: {integrity: sha512-rxZj1GkQhY4x1j/CSnybK9cGuMFQYFPLq0iNyopqf14aOVLFtMv7Esika+ObJWPWiOHuMOAHz3YkWoLYYRnzWQ==}
     dev: false
 
+  /estree-util-to-js/1.1.0:
+    resolution: {integrity: sha512-490lbfCcpLk+ofK6HCgqDfYs4KAfq6QVvDw3+Bm1YoKRgiOjKiKYGAVQE1uwh7zVxBgWhqp4FDtp5SqunpUk1A==}
+    dependencies:
+      '@types/estree-jsx': 1.0.0
+      astring: 1.8.4
+      source-map: 0.7.4
+    dev: false
+
   /estree-util-visit/1.2.0:
     resolution: {integrity: sha512-wdsoqhWueuJKsh5hqLw3j8lwFqNStm92VcwtAOAny8g/KS/l5Y8RISjR4k5W6skCj3Nirag/WUCMS0Nfy3sgsg==}
     dependencies:
@@ -4416,6 +4549,12 @@ packages:
     dependencies:
       reusify: 1.0.4
 
+  /fault/2.0.1:
+    resolution: {integrity: sha512-WtySTkS4OKev5JtpHXnib4Gxiurzh5NCGvWrFaZ34m6JehfTUhKZvn9njTfw48t6JumVQOmrKqpmGcdwxnhqBQ==}
+    dependencies:
+      format: 0.2.2
+    dev: false
+
   /fetch-blob/3.2.0:
     resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==}
     engines: {node: ^12.20 || >= 14.13}
@@ -4518,6 +4657,11 @@ packages:
       mime-types: 2.1.35
     dev: true
 
+  /format/0.2.2:
+    resolution: {integrity: sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==}
+    engines: {node: '>=0.4.x'}
+    dev: false
+
   /formdata-polyfill/4.0.10:
     resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==}
     engines: {node: '>=12.20.0'}
@@ -5015,6 +5159,28 @@ packages:
       zwitch: 2.0.4
     dev: false
 
+  /hast-util-to-estree/2.2.1:
+    resolution: {integrity: sha512-kiGD9WIW3gRKK8Gao3n1f+ahUeTMeJUJILnIT2QNrPigDNdH7rJxzhEbh81UajGeAdAHFecT1a+fLVOCTq9B4Q==}
+    dependencies:
+      '@types/estree': 1.0.0
+      '@types/estree-jsx': 1.0.0
+      '@types/hast': 2.3.4
+      '@types/unist': 2.0.6
+      comma-separated-tokens: 2.0.3
+      estree-util-attach-comments: 2.1.0
+      estree-util-is-identifier-name: 2.0.1
+      hast-util-whitespace: 2.0.1
+      mdast-util-mdx-expression: 1.3.1
+      mdast-util-mdxjs-esm: 1.3.0
+      property-information: 6.2.0
+      space-separated-tokens: 2.0.2
+      style-to-object: 0.4.1
+      unist-util-position: 4.0.3
+      zwitch: 2.0.4
+    transitivePeerDependencies:
+      - supports-color
+    dev: false
+
   /hast-util-to-html/8.0.4:
     resolution: {integrity: sha512-4tpQTUOr9BMjtYyNlt0P50mH7xj0Ks2xpo8M943Vykljf99HW6EzulIoJP1N3eKOSScEHzyzi9dm7/cn0RfGwA==}
     dependencies:
@@ -5239,6 +5405,10 @@ packages:
     engines: {node: '>=10'}
     dev: true
 
+  /inline-style-parser/0.1.1:
+    resolution: {integrity: sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==}
+    dev: false
+
   /inquirer/9.1.4:
     resolution: {integrity: sha512-9hiJxE5gkK/cM2d1mTEnuurGTAoHebbkX0BYl3h7iEg7FYfuNIom+nDfBCSWtvSnoSrWCeBxqqBZu26xdlJlXA==}
     engines: {node: '>=12.0.0'}
@@ -5459,6 +5629,12 @@ packages:
     engines: {node: '>=0.10.0'}
     dev: true
 
+  /is-reference/3.0.1:
+    resolution: {integrity: sha512-baJJdQLiYaJdvFbJqXrcGv3WU3QCzBlUcI5QhbesIm6/xPsvmO+2CDoi/GMOFBQEQm+PXkwOPrp9KK5ozZsp2w==}
+    dependencies:
+      '@types/estree': 1.0.0
+    dev: false
+
   /is-regex/1.1.4:
     resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==}
     engines: {node: '>= 0.4'}
@@ -5917,6 +6093,11 @@ packages:
     engines: {node: '>=8'}
     dev: true
 
+  /markdown-extensions/1.1.1:
+    resolution: {integrity: sha512-WWC0ZuMzCyDHYCasEGs4IPvLyTGftYwh6wIEOULOF0HXcqZlhwRzrK0w2VUlxWA98xnvb/jszw4ZSkJ6ADpM6Q==}
+    engines: {node: '>=0.10.0'}
+    dev: false
+
   /markdown-table/3.0.3:
     resolution: {integrity: sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw==}
     dev: false
@@ -5963,6 +6144,12 @@ packages:
       - supports-color
     dev: false
 
+  /mdast-util-frontmatter/1.0.0:
+    resolution: {integrity: sha512-7itKvp0arEVNpCktOET/eLFAYaZ+0cNjVtFtIPxgQ5tV+3i+D4SDDTjTzPWl44LT59PC+xdx+glNTawBdF98Mw==}
+    dependencies:
+      micromark-extension-frontmatter: 1.0.0
+    dev: false
+
   /mdast-util-gfm-autolink-literal/1.0.2:
     resolution: {integrity: sha512-FzopkOd4xTTBeGXhXSBU0OCDDh5lUj2rd+HQqG92Ld+jL4lpUfgX2AT2OHAVP9aEeDKp7G92fuooSZcYJA3cRg==}
     dependencies:
@@ -6044,6 +6231,43 @@ packages:
       vfile-message: 3.1.3
     dev: false
 
+  /mdast-util-mdx-jsx/2.1.0:
+    resolution: {integrity: sha512-KzgzfWMhdteDkrY4mQtyvTU5bc/W4ppxhe9SzelO6QUUiwLAM+Et2Dnjjprik74a336kHdo0zKm7Tp+n6FFeRg==}
+    dependencies:
+      '@types/estree-jsx': 1.0.0
+      '@types/hast': 2.3.4
+      '@types/mdast': 3.0.10
+      ccount: 2.0.1
+      mdast-util-to-markdown: 1.5.0
+      parse-entities: 4.0.0
+      stringify-entities: 4.0.3
+      unist-util-remove-position: 4.0.1
+      unist-util-stringify-position: 3.0.2
+      vfile-message: 3.1.3
+    dev: false
+
+  /mdast-util-mdx/2.0.0:
+    resolution: {integrity: sha512-M09lW0CcBT1VrJUaF/PYxemxxHa7SLDHdSn94Q9FhxjCQfuW7nMAWKWimTmA3OyDMSTH981NN1csW1X+HPSluw==}
+    dependencies:
+      mdast-util-mdx-expression: 1.3.1
+      mdast-util-mdx-jsx: 2.1.0
+      mdast-util-mdxjs-esm: 1.3.0
+    transitivePeerDependencies:
+      - supports-color
+    dev: false
+
+  /mdast-util-mdxjs-esm/1.3.0:
+    resolution: {integrity: sha512-7N5ihsOkAEGjFotIX9p/YPdl4TqUoMxL4ajNz7PbT89BqsdWJuBC9rvgt6wpbwTZqWWR0jKWqQbwsOWDBUZv4g==}
+    dependencies:
+      '@types/estree-jsx': 1.0.0
+      '@types/hast': 2.3.4
+      '@types/mdast': 3.0.10
+      mdast-util-from-markdown: 1.2.0
+      mdast-util-to-markdown: 1.5.0
+    transitivePeerDependencies:
+      - supports-color
+    dev: false
+
   /mdast-util-phrasing/3.0.0:
     resolution: {integrity: sha512-S+QYsDRLkGi8U7o5JF1agKa/sdP+CNGXXLqC17pdTVL8FHHgQEiwFGa9yE5aYtUxNiFGYoaDy9V1kC85Sz86Gg==}
     dependencies:
@@ -6152,6 +6376,14 @@ packages:
       uvu: 0.5.6
     dev: false
 
+  /micromark-extension-frontmatter/1.0.0:
+    resolution: {integrity: sha512-EXjmRnupoX6yYuUJSQhrQ9ggK0iQtQlpi6xeJzVD5xscyAI+giqco5fdymayZhJMbIFecjnE2yz85S9NzIgQpg==}
+    dependencies:
+      fault: 2.0.1
+      micromark-util-character: 1.1.0
+      micromark-util-symbol: 1.0.1
+    dev: false
+
   /micromark-extension-gfm-autolink-literal/1.0.3:
     resolution: {integrity: sha512-i3dmvU0htawfWED8aHMMAzAVp/F0Z+0bPh3YrbTPPL1v4YAlCZpy5rBO5p0LPYiZo0zFVkoYh7vDU7yQSiCMjg==}
     dependencies:
@@ -6237,12 +6469,52 @@ packages:
       uvu: 0.5.6
     dev: false
 
+  /micromark-extension-mdx-jsx/1.0.3:
+    resolution: {integrity: sha512-VfA369RdqUISF0qGgv2FfV7gGjHDfn9+Qfiv5hEwpyr1xscRj/CiVRkU7rywGFCO7JwJ5L0e7CJz60lY52+qOA==}
+    dependencies:
+      '@types/acorn': 4.0.6
+      estree-util-is-identifier-name: 2.0.1
+      micromark-factory-mdx-expression: 1.0.6
+      micromark-factory-space: 1.0.0
+      micromark-util-character: 1.1.0
+      micromark-util-symbol: 1.0.1
+      micromark-util-types: 1.0.2
+      uvu: 0.5.6
+      vfile-message: 3.1.3
+    dev: false
+
   /micromark-extension-mdx-md/1.0.0:
     resolution: {integrity: sha512-xaRAMoSkKdqZXDAoSgp20Azm0aRQKGOl0RrS81yGu8Hr/JhMsBmfs4wR7m9kgVUIO36cMUQjNyiyDKPrsv8gOw==}
     dependencies:
       micromark-util-types: 1.0.2
     dev: false
 
+  /micromark-extension-mdxjs-esm/1.0.3:
+    resolution: {integrity: sha512-2N13ol4KMoxb85rdDwTAC6uzs8lMX0zeqpcyx7FhS7PxXomOnLactu8WI8iBNXW8AVyea3KIJd/1CKnUmwrK9A==}
+    dependencies:
+      micromark-core-commonmark: 1.0.6
+      micromark-util-character: 1.1.0
+      micromark-util-events-to-acorn: 1.2.0
+      micromark-util-symbol: 1.0.1
+      micromark-util-types: 1.0.2
+      unist-util-position-from-estree: 1.1.1
+      uvu: 0.5.6
+      vfile-message: 3.1.3
+    dev: false
+
+  /micromark-extension-mdxjs/1.0.0:
+    resolution: {integrity: sha512-TZZRZgeHvtgm+IhtgC2+uDMR7h8eTKF0QUX9YsgoL9+bADBpBY6SiLvWqnBlLbCEevITmTqmEuY3FoxMKVs1rQ==}
+    dependencies:
+      acorn: 8.8.1
+      acorn-jsx: 5.3.2_acorn@8.8.1
+      micromark-extension-mdx-expression: 1.0.3
+      micromark-extension-mdx-jsx: 1.0.3
+      micromark-extension-mdx-md: 1.0.0
+      micromark-extension-mdxjs-esm: 1.0.3
+      micromark-util-combine-extensions: 1.0.0
+      micromark-util-types: 1.0.2
+    dev: false
+
   /micromark-factory-destination/1.0.0:
     resolution: {integrity: sha512-eUBA7Rs1/xtTVun9TmV3gjfPz2wEwgK5R5xcbIM5ZYAtvGF6JkyaDsj0agx8urXnO31tEO6Ug83iVH3tdedLnw==}
     dependencies:
@@ -7117,6 +7389,13 @@ packages:
     resolution: {integrity: sha512-NOT9AcKiDGpnV/HBhI22Str++XWcErO/bALvHCuhv33owZW/CjH8KAFLZDCmu3727sihe0wTxpDhyGc6M8qacQ==}
     dev: true
 
+  /periscopic/3.0.4:
+    resolution: {integrity: sha512-SFx68DxCv0Iyo6APZuw/AKewkkThGwssmU0QWtTlvov3VAtPX+QJ4CadwSaz8nrT5jPIuxdvJWB4PnD2KNDxQg==}
+    dependencies:
+      estree-walker: 3.0.2
+      is-reference: 3.0.1
+    dev: false
+
   /picocolors/1.0.0:
     resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==}
 
@@ -7599,6 +7878,15 @@ packages:
       - supports-color
     dev: true
 
+  /remark-frontmatter/4.0.1:
+    resolution: {integrity: sha512-38fJrB0KnmD3E33a5jZC/5+gGAC2WKNiPw1/fdXJvijBlhA7RCsvJklrYJakS0HedninvaCYW8lQGf9C918GfA==}
+    dependencies:
+      '@types/mdast': 3.0.10
+      mdast-util-frontmatter: 1.0.0
+      micromark-extension-frontmatter: 1.0.0
+      unified: 10.1.2
+    dev: false
+
   /remark-gfm/3.0.1:
     resolution: {integrity: sha512-lEFDoi2PICJyNrACFOfDD3JlLkuSbOa5Wd8EPt06HUdptv8Gn0bxYTdbU/XXQ3swAPkEaGxxPN9cbnMHvVu1Ig==}
     dependencies:
@@ -7610,6 +7898,15 @@ packages:
       - supports-color
     dev: false
 
+  /remark-mdx/2.2.1:
+    resolution: {integrity: sha512-R9wcN+/THRXTKyRBp6Npo/mcbGA2iT3N4G8qUqLA5pOEg7kBidHv8K2hHidCMYZ6DXmwK18umu0K4cicgA2PPQ==}
+    dependencies:
+      mdast-util-mdx: 2.0.0
+      micromark-extension-mdxjs: 1.0.0
+    transitivePeerDependencies:
+      - supports-color
+    dev: false
+
   /remark-parse/10.0.1:
     resolution: {integrity: sha512-1fUyHr2jLsVOkhbvPRBJ5zTKZZyD6yZzYaWCS6BPBdQ8vEMBCH+9zNCDA6tET/zHCi/jLqjCWtlJZUPk+DbnFw==}
     dependencies:
@@ -8270,6 +8567,12 @@ packages:
       acorn: 8.8.1
     dev: true
 
+  /style-to-object/0.4.1:
+    resolution: {integrity: sha512-HFpbb5gr2ypci7Qw+IOhnP2zOU7e77b+rzM+wTzXzfi1PrtBCX0E7Pk4wL4iTLnhzZ+JgEGAhX81ebTg/aYjQw==}
+    dependencies:
+      inline-style-parser: 0.1.1
+    dev: false
+
   /suf-log/2.5.3:
     resolution: {integrity: sha512-KvC8OPjzdNOe+xQ4XWJV2whQA0aM1kGVczMQ8+dStAO6KfEB140JEVQ9dE76ONZ0/Ylf67ni4tILPJB41U0eow==}
     dependencies:
@@ -8804,6 +9107,17 @@ packages:
     engines: {node: '>= 10.0.0'}
     dev: true
 
+  /unocss-preset-daisy/1.2.0_77u2kep7hemix4zf3mpsyjlcju:
+    resolution: {integrity: sha512-qjjp9sXwBs8juXKaTeKgIYOT2JuOA+tdsodqkizHh7Rjn+PjHJhDuJZeHP9ogaZbbm0Ja3sxWGw1IDzsicJV3g==}
+    peerDependencies:
+      '@kidonng/daisyui': ^2.27.0
+      unocss: ^0.45.21
+    dependencies:
+      '@kidonng/daisyui': 2.31.0
+      camelcase: 7.0.1
+      unocss: 0.48.0
+    dev: true
+
   /unocss/0.48.0:
     resolution: {integrity: sha512-rDyMHyvRTRUPOd406CzgoYfiQ4tzN/TGU++jFTDzLsJ9Unuwf/pBBclP6z6aqt5eRBoEOEMqrJJwm9QN7aeYdA==}
     engines: {node: '>=14'}
@@ -9006,6 +9320,17 @@ packages:
       - supports-color
     dev: true
 
+  /vite-plugin-glsl/1.0.1:
+    resolution: {integrity: sha512-mEwarIBeQCqgakn1r4B2Gja8QbrC2pjd/CezIudTMNXn5BR44gphQElMjzxoJgsBX7z/T5ROT8YvQifdpwXY3g==}
+    engines: {node: '>= 16.15.1', npm: '>= 8.11.0'}
+    peerDependencies:
+      vite: ^3.0.0 || ^4.0.0
+    dependencies:
+      '@rollup/pluginutils': 5.0.2
+    transitivePeerDependencies:
+      - rollup
+    dev: true
+
   /vite-plugin-glsl/1.1.0_vite@4.0.4:
     resolution: {integrity: sha512-51J4VhixNorGtks+gbCKv6RHJxVaZMn/Z1bz2IA/Vn4BCsqOa8pc3ioZkaGMQR47ERg/IafRxOrTU7Dhk4K0Vw==}
     engines: {node: '>= 16.15.1', npm: '>= 8.11.0'}