Quellcode durchsuchen

feat(playground): add materials and portal journey

Alvaro vor 2 Jahren
Ursprung
Commit
4292321d80

+ 3 - 0
.vscode/settings.json

@@ -19,5 +19,8 @@
   "testing.automaticallyOpenPeekView": "never",
   "files.associations": {
     "*.mdx": "markdown"
+  },
+  "[astro]": {
+    "editor.defaultFormatter": "astro-build.astro-vscode"
   }
 }

+ 62 - 11
apps/playground/astro.config.mjs

@@ -1,17 +1,68 @@
-import { defineConfig } from 'astro/config';
-import UnoCSS from 'unocss/astro';
-
+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';
+import vue from '@astrojs/vue'
 
 // https://astro.build/config
-import mdx from "@astrojs/mdx";
+import mdx from '@astrojs/mdx'
 
 // https://astro.build/config
 export default defineConfig({
-  integrations: [vue({
-    appEntrypoint: '/src/pages/_app'
-  }), UnoCSS({
-    /* options */
-  }), mdx()]
-});
+  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(),
+  ],
+})

+ 2 - 1
apps/playground/package.json

@@ -33,6 +33,7 @@
     "@tresjs/core": "workspace:^1.5.0",
     "three": "^0.148.0",
     "unocss": "^0.48.0",
-    "unocss-preset-daisy": "^1.2.0"
+    "unocss-preset-daisy": "^1.2.0",
+    "vite-plugin-glsl": "^1.0.1"
   }
 }

BIN
apps/playground/public/materials.png


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


+ 19 - 14
apps/playground/src/components/Header.astro

@@ -1,23 +1,28 @@
 ---
-import Logo from '/logo.svg';
+import Logo from '/logo.svg'
 
 export interface Props {
-    title: string;
-	visible: boolean;
+  title: string
+  visible: boolean
 }
 
-const { visible = false, title } = Astro.props;
-
+const { visible = false, title } = Astro.props
 ---
 
-<header class={`fixed top-0 z-10 w-full bg-gray-50 py-4 text-gray-600 ${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>
+<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>

+ 16 - 6
apps/playground/src/components/TheInfo.astro

@@ -1,11 +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 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="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>
-

+ 1 - 0
apps/playground/src/components/TresDonut.vue

@@ -4,6 +4,7 @@ import { reactive } from 'vue'
 const state = reactive({
   shadows: true,
   alpha: false,
+  clearColor: '#4f4f4f',
 })
 </script>
 

+ 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;
+}

+ 27 - 29
apps/playground/src/layouts/ExperimentLayout.astro

@@ -1,38 +1,36 @@
 ---
-import ExperimentInfo from '../components/ExperimentInfo.vue';
-import Header from '../components/Header.astro';
-
-const {frontmatter} = Astro.props;
+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} />
-		<title>{frontmatter.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>{frontmatter.title}</title>
+  </head>
+  <body>
+    <slot />
+  </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;
-	}
+  :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>

+ 0 - 1
apps/playground/src/pages/_app.ts

@@ -1,6 +1,5 @@
 import type { App } from 'vue'
 import Tres from '@tresjs/core'
-import '@kidonng/daisyui/index.css'
 
 export default (app: App) => {
   app.use(Tres)

+ 32 - 29
apps/playground/src/pages/index.astro

@@ -1,35 +1,38 @@
 ---
-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,
-}));
+const vueExperiments = await Astro.glob('./vue/**/*.mdx')
+const experiments = [...vueExperiments].map(experiment => ({
+  framework: 'vue',
+  ...experiment,
+}))
 ---
 
 <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-16 md:gap-32">
-		{experiments.map((experiment) => (
-			<a href={experiment.url} class="card bg-base-100 text-gray-700 shadow-xl rounded-lg overflow-hidden relative"
-			>
-				<span class="absolute top-4 right-4 rounded-full flex p-2 bg-white"><i class={`i-logos-${experiment.framework}`} /></span>
-				<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 font-semibold bg-lime-200 py-1 px-2 rounded mr-2">{tag}</span>
-								</li>
-							))}
-						</ul>
-					</footer>
-				</div>
-			</a>
-		  ))}
-	</main>
+  <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>
-

+ 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>

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

@@ -12,7 +12,7 @@ import TheInfo from '/@/components/TheInfo.astro'
 
 <TresDonut client:only />
 
-<TheInfo >
+<TheInfo>
 # { frontmatter.title }
 
 ```vue

+ 0 - 46
apps/playground/unocss.config.ts

@@ -1,46 +0,0 @@
-import {
-  defineConfig,
-  presetAttributify,
-  presetIcons,
-  presetTypography,
-  presetUno,
-  presetWebFonts,
-  transformerDirectives,
-  transformerVariantGroup,
-} from 'unocss'
-import presetDaisy from 'unocss-preset-daisy'
-
-export default defineConfig({
-  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(' '),
-})

+ 13 - 0
pnpm-lock.yaml

@@ -58,6 +58,7 @@ importers:
       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
@@ -73,6 +74,7 @@ importers:
       three: 0.148.0
       unocss: 0.48.0
       unocss-preset-daisy: 1.2.0_77u2kep7hemix4zf3mpsyjlcju
+      vite-plugin-glsl: 1.0.1
 
   packages/cientos:
     specifiers:
@@ -10045,6 +10047,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.0.1_vite@4.0.3:
     resolution: {integrity: sha512-mEwarIBeQCqgakn1r4B2Gja8QbrC2pjd/CezIudTMNXn5BR44gphQElMjzxoJgsBX7z/T5ROT8YvQifdpwXY3g==}
     engines: {node: '>= 16.15.1', npm: '>= 8.11.0'}