فهرست منبع

refactor: playground housekeeping (#719)

* refactor: playground housekeeping

* move single-use components into folders with their parent components
* add "Issues" category

* chore: run linter

---------

Co-authored-by: Alvaro Saburido <alvaro.saburido@gmail.com>
andretchen0 11 ماه پیش
والد
کامیت
74a2c47863
31فایلهای تغییر یافته به همراه99 افزوده شده و 550 حذف شده
  1. 1 0
      playground/components.d.ts
  2. 0 17
      playground/src/components/AkuAku.vue
  3. 0 27
      playground/src/components/AnimatedObjectUseUpdate.vue
  4. 0 319
      playground/src/components/LocalOrbitControls.vue
  5. 0 0
      playground/src/components/PbrSphere.vue
  6. 1 1
      playground/src/pages/advanced/fbo/FBOCube.vue
  7. 1 1
      playground/src/pages/advanced/fbo/index.vue
  8. 0 0
      playground/src/pages/advanced/fbo/useFBO.ts
  9. 11 0
      playground/src/pages/advanced/suspense/AsyncComponent.vue
  10. 15 17
      playground/src/pages/advanced/suspense/index.vue
  11. 0 0
      playground/src/pages/advanced/takeOverRender/TakeOverRenderExperience.vue
  12. 1 0
      playground/src/pages/advanced/takeOverRender/index.vue
  13. 1 2
      playground/src/pages/cameras/NoCamera.vue
  14. 0 0
      playground/src/pages/cameras/multipleCameras/TheCameraOperator.vue
  15. 4 2
      playground/src/pages/cameras/multipleCameras/index.vue
  16. 0 0
      playground/src/pages/events/propagation/Box.vue
  17. 1 1
      playground/src/pages/events/propagation/index.vue
  18. 25 33
      playground/src/pages/index.vue
  19. 0 0
      playground/src/pages/issues/717/MyBox.vue
  20. 1 2
      playground/src/pages/issues/717/index.vue
  21. 1 1
      playground/src/pages/misc/directives/DirectiveSubComponent.vue
  22. 1 1
      playground/src/pages/misc/directives/index.vue
  23. 0 0
      playground/src/pages/misc/text3D/Text3D.vue
  24. 1 0
      playground/src/pages/misc/text3D/index.vue
  25. 2 114
      playground/src/router/index.ts
  26. 9 4
      playground/src/router/routes/advanced.ts
  27. 0 5
      playground/src/router/routes/basic.ts
  28. 1 1
      playground/src/router/routes/cameras.ts
  29. 13 0
      playground/src/router/routes/index.ts
  30. 7 0
      playground/src/router/routes/issues.ts
  31. 2 2
      playground/src/router/routes/misc.ts

+ 1 - 0
playground/components.d.ts

@@ -18,6 +18,7 @@ declare module 'vue' {
     LocalOrbitControls: typeof import('./src/components/LocalOrbitControls.vue')['default']
     Overlay: typeof import('./src/components/Overlay.vue')['default']
     OverlayInfo: typeof import('./src/components/OverlayInfo.vue')['default']
+    PbrSphere: typeof import('./src/components/PbrSphere.vue')['default']
     RouterLink: typeof import('vue-router')['RouterLink']
     RouterView: typeof import('vue-router')['RouterView']
     TakeOverLoopExperience: typeof import('./src/components/TakeOverLoopExperience.vue')['default']

+ 0 - 17
playground/src/components/AkuAku.vue

@@ -1,17 +0,0 @@
-<script setup lang="ts">
-import { useTresContext } from '@tresjs/core'
-import { useGLTF } from '@tresjs/cientos'
-
-const { nodes } = await useGLTF('https://raw.githubusercontent.com/Tresjs/assets/main/models/gltf/AkuAku.glb', { draco: true })
-const model = nodes.Cube
-
-model.position.set(0, 1, 0)
-
-const state = useTresContext()
-
-state.invalidate()
-</script>
-
-<template>
-  <primitive :object="model" />
-</template>

+ 0 - 27
playground/src/components/AnimatedObjectUseUpdate.vue

@@ -53,33 +53,6 @@ watchEffect(() => {
     off()
   }
 })
-/* const anotherLog = useThrottleFn(() => console.log('after render'), 3000)
- */
-/* useUpdate(() => {
-  anotherLog()
-}, 1) */
-
-/* useUpdate(() => {
-  console.count('update loop 1')
-})
-
-useUpdate(() => {
-  console.count('update loop 2')
-}) */
-
-/* useUpdate(() => {
-  console.count('before renderer')
-}, -1)
-
-useUpdate(() => {
-  console.log('this should be just before render')
-})
-
-useUpdate((state) => {
-  if (!sphereRef.value) { return }
-  console.count('after renderer')
-  sphereRef.value.position.y += Math.sin(state.elapsed) * 0.01
-}, 2) */
 </script>
 
 <template>

+ 0 - 319
playground/src/components/LocalOrbitControls.vue

@@ -1,319 +0,0 @@
-<script lang="ts" setup>
-import type { Camera } from 'three'
-import { OrbitControls } from 'three-stdlib'
-import { onUnmounted, ref, unref } from 'vue'
-import type { TresVector3 } from '@tresjs/core'
-import { extend, useRenderLoop, useTresContext } from '@tresjs/core'
-import { useEventListener } from '@vueuse/core'
-
-export interface OrbitControlsProps {
-  /**
-   * Whether to make this the default controls.
-   *
-   * @default false
-   * @type {boolean}
-   * @memberof OrbitControlsProps
-   */
-  makeDefault?: boolean
-  /**
-   * The camera to control.
-   *
-   * @type {Camera}
-   * @memberof OrbitControlsProps
-   * @see https://threejs.org/docs/#examples/en/controls/OrbitControls.camera
-   */
-  camera?: Camera
-  /**
-   * The dom element to listen to.
-   *
-   * @type {HTMLElement}
-   * @memberof OrbitControlsProps
-   * @see https://threejs.org/docs/#examples/en/controls/OrbitControls.domElement
-   */
-  domElement?: HTMLElement
-  /**
-   * The target to orbit around.
-   *
-   * @type {TresVector3}
-   * @memberof OrbitControlsProps
-   * @see https://threejs.org/docs/#examples/en/controls/OrbitControls.target
-   */
-  target?: TresVector3
-  /**
-   * Whether to enable damping (inertia)
-   *
-   * @default false
-   * @type {boolean}
-   * @memberof OrbitControlsProps
-   * @see https://threejs.org/docs/#examples/en/controls/OrbitControls.enableDamping
-   */
-  enableDamping?: boolean
-  /**
-   * The damping inertia used if `.enableDamping` is set to true
-   *
-   * @default 0.05
-   * @type {number}
-   * @memberof OrbitControlsProps
-   * @see https://threejs.org/docs/#examples/en/controls/OrbitControls.dampingFactor
-   */
-  dampingFactor?: number
-  /**
-   * Set to true to automatically rotate around the target.
-   *
-   * @default false
-   * @type {boolean}
-   * @memberof OrbitControlsProps
-   * @see https://threejs.org/docs/#examples/en/controls/OrbitControls.autoRotate
-   */
-  autoRotate?: boolean
-  /**
-   * How fast to rotate around the target if `.autoRotate` is true.
-   *
-   * @default 2
-   * @type {number}
-   * @memberof OrbitControlsProps
-   * @see https://threejs.org/docs/#examples/en/controls/OrbitControls.autoRotateSpeed
-   */
-  autoRotateSpeed?: number
-  /**
-   * Whether to enable panning.
-   *
-   * @default true
-   * @type {boolean}
-   * @memberof OrbitControlsProps
-   * @see https://threejs.org/docs/#examples/en/controls/OrbitControls.enablePan
-   */
-  enablePan?: boolean
-  /**
-   * How fast to pan the camera when the keyboard is used. Default is 7.0 pixels per keypress.
-   *
-   * @default 7.0
-   * @type {number}
-   * @memberof OrbitControlsProps
-   * @see https://threejs.org/docs/#examples/en/controls/OrbitControls.keyPanSpeed
-   */
-  keyPanSpeed?: number
-  /**
-   * This object contains references to the keycodes for controlling camera panning.
-   * Default is the 4 arrow keys.
-   *
-   * @default `{ LEFT: 'ArrowLeft', UP: 'ArrowUp', RIGHT: 'ArrowRight', BOTTOM: 'ArrowDown' }`
-   * @type Record<string, string>
-   * @memberof OrbitControlsProps
-   * @see https://threejs.org/docs/#examples/en/controls/OrbitControls.keys
-   */
-  keys?: Record<string, string>
-  /**
-   * How far you can orbit horizontally, upper limit.
-   * If set, the interval [ min, max ] must be a sub-interval of [ - 2 PI, 2 PI ],
-   * with ( max - min < 2 PI ). Default is Infinity.
-   *
-   * @default Infinity
-   * @type {number}
-   * @memberof OrbitControlsProps
-   * @see https://threejs.org/docs/index.html?q=orbi#examples/en/controls/OrbitControls.maxAzimuthAngle
-   */
-  maxAzimuthAngle?: number
-  /**
-   * How far you can orbit horizontally, lower limit.
-   * If set, the interval [ min, max ] must be a sub-interval of [ - 2 PI, 2 PI ],
-   * with ( max - min < 2 PI ).
-   * Default is - Infinity.
-   *
-   * @default -Infinity
-   * @type {number}
-   * @memberof OrbitControlsProps
-   * @see https://threejs.org/docs/index.html?q=orbi#examples/en/controls/OrbitControls.minAzimuthAngle
-   */
-  minAzimuthAngle?: number
-  /**
-   * How far you can orbit vertically, upper limit.
-   * Range is 0 to Math.PI radians, and default is Math.PI.
-   *
-   * @default Math.PI
-   * @type {number}
-   * @memberof OrbitControlsProps
-   * @see https://threejs.org/docs/index.html?q=orbi#examples/en/controls/OrbitControls.maxPolarAngle
-   */
-  maxPolarAngle?: number
-  /**
-   * How far you can orbit vertically, lower limit.
-   * Range is 0 to Math.PI radians, and default is 0.
-   *
-   * @default 0
-   * @type {number}
-   * @memberof OrbitControlsProps
-   * @see https://threejs.org/docs/index.html?q=orbi#examples/en/controls/OrbitControls.minPolarAngle
-   */
-  minPolarAngle?: number
-  /**
-   * The minimum distance of the camera to the target.
-   * Default is 0.
-   *
-   * @default 0
-   * @type {number}
-   * @memberof OrbitControlsProps
-   * @see https://threejs.org/docs/index.html?q=orbi#examples/en/controls/OrbitControls.minDistance
-   */
-  minDistance?: number
-  /**
-   * The maximum distance of the camera to the target.
-   * Default is Infinity.
-   *
-   * @default Infinity
-   * @type {number}
-   * @memberof OrbitControlsProps
-   * @see https://threejs.org/docs/index.html?q=orbi#examples/en/controls/OrbitControls.maxDistance
-   */
-  maxDistance?: number
-  /**
-   * The minimum field of view angle, in radians.
-   * Default is 0.
-   *
-   * @default 0
-   * @type {number}
-   * @memberof OrbitControlsProps
-   * @see https://threejs.org/docs/index.html?q=orbi#examples/en/controls/OrbitControls.minZoom
-   */
-  minZoom?: number
-  /**
-   * The maximum field of view angle, in radians.
-   * ( OrthographicCamera only ).
-   * Default is Infinity.
-   *
-   * @default Infinity
-   * @type {number}
-   * @memberof OrbitControlsProps
-   * @see https://threejs.org/docs/index.html?q=orbi#examples/en/controls/OrbitControls.maxZoom
-   */
-  maxZoom?: number
-  touches?: {
-    ONE?: number
-    TWO?: number
-  }
-  /**
-   * Whether to enable zooming.
-   *
-   * @default true
-   * @type {boolean}
-   * @memberof OrbitControlsProps
-   * @see https://threejs.org/docs/#examples/en/controls/OrbitControls.enableZoom
-   */
-  enableZoom?: boolean
-  /**
-   * How fast to zoom in and out. Default is 1.
-   *
-   * @default 1
-   * @type {number}
-   * @memberof OrbitControlsProps
-   * @see https://threejs.org/docs/#examples/en/controls/OrbitControls.zoomSpeed
-   */
-  zoomSpeed?: number
-  /**
-   * Whether to enable rotating.
-   *
-   * @default true
-   * @type {boolean}
-   * @memberof OrbitControlsProps
-   * @see https://threejs.org/docs/#examples/en/controls/OrbitControls.enableRotate
-   */
-  enableRotate?: boolean
-  /**
-   * How fast to rotate around the target. Default is 1.
-   *
-   * @default 1
-   * @type {number}
-   * @memberof OrbitControlsProps
-   * @see https://threejs.org/docs/#examples/en/controls/OrbitControls.rotateSpeed
-   */
-  rotateSpeed?: number
-}
-
-// TODO: remove disable once eslint is updated to support vue 3.3
-
-const {
-  autoRotate = false,
-  autoRotateSpeed = 2,
-  enableDamping = false,
-  dampingFactor = 0.05,
-  enablePan = true,
-  keyPanSpeed = 7,
-  maxAzimuthAngle = Number.POSITIVE_INFINITY,
-  minAzimuthAngle = Number.NEGATIVE_INFINITY,
-  maxPolarAngle = Math.PI,
-  minPolarAngle = 0,
-  minDistance = 0,
-  maxDistance = Number.POSITIVE_INFINITY,
-  minZoom = 0,
-  maxZoom = Number.POSITIVE_INFINITY,
-  enableZoom = true,
-  zoomSpeed = 1,
-  enableRotate = true,
-  rotateSpeed = 1,
-  target = [0, 0, 0],
-} = defineProps<OrbitControlsProps>()
-
-const emit = defineEmits(['change', 'start', 'end'])
-
-const { renderer, camera: activeCamera } = useTresContext()
-
-const controls = ref<OrbitControls | null>(null)
-
-extend({ OrbitControls })
-
-function addEventListeners() {
-  useEventListener(controls.value as any, 'change', () =>
-    emit('change', controls.value))
-  useEventListener(controls.value as any, 'start', () =>
-    emit('start', controls.value))
-  useEventListener(controls.value as any, 'end', () =>
-    emit('end', controls.value))
-}
-
-const { onLoop } = useRenderLoop()
-
-onLoop(() => {
-  if (controls.value && (enableDamping || autoRotate)) {
-    controls.value.update()
-  }
-})
-
-onMounted(() => {
-  addEventListeners()
-})
-
-onUnmounted(() => {
-  if (controls.value) {
-    controls.value.dispose()
-  }
-})
-</script>
-
-<template>
-  <TresOrbitControls
-    v-if="activeCamera && renderer"
-    ref="controls"
-    :target="target"
-    :auto-rotate="autoRotate"
-    :auto-rotate-speed="autoRotateSpeed"
-    :enable-damping="enableDamping"
-    :damping-factor="dampingFactor"
-    :enable-pan="enablePan"
-    :key-pan-speed="keyPanSpeed"
-    :keys="keys"
-    :max-azimuth-angle="maxAzimuthAngle"
-    :min-azimuth-angle="minAzimuthAngle"
-    :max-polar-angle="maxPolarAngle"
-    :min-polar-angle="minPolarAngle"
-    :min-distance="minDistance"
-    :max-distance="maxDistance"
-    :min-zoom="minZoom"
-    :max-zoom="maxZoom"
-    :touches="touches"
-    :enable-zoom="enableZoom"
-    :zoom-speed="zoomSpeed"
-    :enable-rotate="enableRotate"
-    :rotate-speed="rotateSpeed"
-    :args="[unref(activeCamera) || camera, renderer?.domElement || domElement]"
-  />
-</template>

+ 0 - 0
playground/src/components/TestSphere.vue → playground/src/components/PbrSphere.vue


+ 1 - 1
playground/src/components/FBOCube.vue → playground/src/pages/advanced/fbo/FBOCube.vue

@@ -1,6 +1,6 @@
 <!-- eslint-disable no-console -->
 <script setup lang="ts">
-import { useFBO } from '../composables/useFBO'
+import { useFBO } from './useFBO'
 
 const fboTarget = useFBO({
   depth: true,

+ 1 - 1
playground/src/pages/advanced/FBO.vue → playground/src/pages/advanced/fbo/index.vue

@@ -1,8 +1,8 @@
 <script setup lang="ts">
 import { TresCanvas } from '@tresjs/core'
 import { BasicShadowMap, NoToneMapping, SRGBColorSpace } from 'three'
-
 import { OrbitControls } from '@tresjs/cientos'
+import FBOCube from './FBOCube.vue'
 import '@tresjs/leches/styles'
 
 const gl = {

+ 0 - 0
playground/src/composables/useFBO.ts → playground/src/pages/advanced/fbo/useFBO.ts


+ 11 - 0
playground/src/pages/advanced/suspense/AsyncComponent.vue

@@ -0,0 +1,11 @@
+<script setup lang="ts">
+import { useTresContext } from '@tresjs/core'
+import { useGLTF } from '@tresjs/cientos'
+
+const { scene } = await useGLTF('https://raw.githubusercontent.com/Tresjs/assets/main/models/gltf/aku-aku/AkuAku.gltf', { draco: true })
+useTresContext().invalidate()
+</script>
+
+<template>
+  <primitive :object="scene" :position-y="-2" />
+</template>

+ 15 - 17
playground/src/pages/advanced/index.vue → playground/src/pages/advanced/suspense/index.vue

@@ -4,7 +4,7 @@ import { BasicShadowMap, NoToneMapping, SRGBColorSpace } from 'three'
 import { Perf, TresLeches, useControls } from '@tresjs/leches'
 import '@tresjs/leches/styles'
 import { OrbitControls } from '@tresjs/cientos'
-import AkuAku from './AkuAku.vue'
+import AsyncComponent from './AsyncComponent.vue'
 
 const gl = {
   clearColor: '#82DBC5',
@@ -15,14 +15,16 @@ const gl = {
   toneMapping: NoToneMapping,
 }
 
-const { sphere } = useControls({
-  sphere: true,
+const { show } = useControls({
+  show: true,
 })
 
 const ctx = ref(null)
 
 watchEffect(() => {
-  if (!ctx.value) { return }
+  if (!ctx.value) {
+    return
+  }
   // eslint-disable-next-line no-console
   console.log('ctx', ctx.value)
 })
@@ -35,29 +37,25 @@ useControls({
       ctx?.value?.dispose()
     },
   },
-
 })
 </script>
 
 <template>
   <TresLeches />
-  <TresCanvas
-    v-bind="gl"
-    ref="ctx"
-  >
+  <TresCanvas v-bind="gl" ref="ctx">
     <Perf />
     <TresPerspectiveCamera :position="[3, 3, 3]" />
     <OrbitControls />
     <Suspense>
-      <AkuAku v-if="sphere" />
+      <AsyncComponent v-if="show" />
     </Suspense>
-    <!--  <TresMesh
-      v-if="sphere.value"
-      :position="[0, 0, 0]"
-    >
-      <TresSphereGeometry />
-      <TresMeshStandardMaterial color="teal" />
-    </TresMesh> -->
     <TresAmbientLight :intensity="1" />
   </TresCanvas>
+  <OverlayInfo>
+    <h1>Suspense</h1>
+    <p>
+      Because the model in this page is loaded asynchronously behind the scenes
+      with <code>useGLTF</code>, it must be wrapped in a Suspense component.
+    </p>
+  </OverlayInfo>
 </template>

+ 0 - 0
playground/src/components/TakeOverLoopExperience.vue → playground/src/pages/advanced/takeOverRender/TakeOverRenderExperience.vue


+ 1 - 0
playground/src/pages/advanced/TakeOverLoop.vue → playground/src/pages/advanced/takeOverRender/index.vue

@@ -2,6 +2,7 @@
 import { TresCanvas } from '@tresjs/core'
 import { BasicShadowMap, NoToneMapping, SRGBColorSpace } from 'three'
 import { TresLeches, useControls } from '@tresjs/leches'
+import TakeOverLoopExperience from './TakeOverRenderExperience.vue'
 import '@tresjs/leches/styles'
 
 const gl = {

+ 1 - 2
playground/src/pages/cameras/NoCamera.vue

@@ -26,7 +26,6 @@ const useOwnCamera = ref(false)
         v-bind="state"
         :camera="useOwnCamera ? camera : undefined"
       >
-        <LocalOrbitControls />
         <TresAmbientLight :intensity="0.5" />
         <TresMesh :position="[0, 4, 0]">
           <TresBoxGeometry :args="[1, 1, 1]" />
@@ -34,7 +33,7 @@ const useOwnCamera = ref(false)
         </TresMesh>
 
         <Suspense>
-          <TestSphere />
+          <PbrSphere />
         </Suspense>
         <TresDirectionalLight
           :position="[0, 2, 4]"

+ 0 - 0
playground/src/components/TheCameraOperator.vue → playground/src/pages/cameras/multipleCameras/TheCameraOperator.vue


+ 4 - 2
playground/src/pages/cameras/MultipleCameras.vue → playground/src/pages/cameras/multipleCameras/index.vue

@@ -2,7 +2,9 @@
 import type { Camera } from 'three'
 import { TresCanvas } from '@tresjs/core'
 import { TresLeches, useControls } from '@tresjs/leches'
+import { OrbitControls } from '@tresjs/cientos'
 import '@tresjs/leches/styles'
+import TheCameraOperator from './TheCameraOperator.vue'
 
 const state = reactive({
   clearColor: '#4f4f4f',
@@ -75,7 +77,7 @@ const camera3Exists = ref(false)
             :look-at="[0, 4, 0]"
           />
         </TheCameraOperator>
-        <LocalOrbitControls />
+        <OrbitControls />
         <TresAmbientLight :intensity="0.5" />
         <TresMesh :position="[0, 4, 0]">
           <TresBoxGeometry :args="[1, 1, 1]" />
@@ -83,7 +85,7 @@ const camera3Exists = ref(false)
         </TresMesh>
 
         <Suspense>
-          <TestSphere />
+          <PbrSphere />
         </Suspense>
         <TresDirectionalLight
           :position="[0, 2, 4]"

+ 0 - 0
playground/src/components/Box.vue → playground/src/pages/events/propagation/Box.vue


+ 1 - 1
playground/src/pages/events/Propagation.vue → playground/src/pages/events/propagation/index.vue

@@ -6,7 +6,7 @@ import {
 import { BasicShadowMap, NoToneMapping, SRGBColorSpace } from 'three'
 import { OrbitControls } from '@tresjs/cientos'
 import '@tresjs/leches/styles'
-import Box from '../../components/Box.vue'
+import Box from './Box.vue'
 
 const gl = {
   clearColor: '#202020',

+ 25 - 33
playground/src/pages/index.vue

@@ -4,6 +4,7 @@ import {
   basicRoutes,
   cameraRoutes,
   eventsRoutes,
+  issuesRoutes,
   miscRoutes,
   modelsRoutes,
 } from '../router/routes'
@@ -15,23 +16,17 @@ const sections = [
   { icon: '📷', title: 'Camera', routes: cameraRoutes },
   { icon: '🐇', title: 'Models', routes: modelsRoutes },
   { icon: '🤪', title: 'Misc', routes: miscRoutes },
+  { icon: '🔬', title: 'Issues', routes: issuesRoutes },
 ]
 </script>
 
 <template>
   <div
-    class="
-  container mx-auto max-w-3xl
-  font-sans text-xs color-gray
-  bg-white
-  "
+    class="container mx-auto max-w-3xl font-sans text-xs color-gray bg-white"
   >
     <div class="mx-4">
       <div
-        class="
-    mt-24 mb-12 text-center align-baseline items-center gap-6
-    sm:mt-16 sm:mb-6 sm:text-left sm:flex sm:flex-row-reverse sm:justify-left
-    "
+        class="mt-24 mb-12 text-center align-baseline items-center gap-6 sm:mt-16 sm:mb-6 sm:text-left sm:flex sm:flex-row-reverse sm:justify-left"
       >
         <div>
           <img
@@ -42,44 +37,41 @@ const sections = [
         </div>
         <div class="sm:w-2/3">
           <h1
-            class="
-        w-auto max-w-75 mx-auto text-5xl text-zinc-700 mb-3
-        sm:mx-none sm:w-1/2 sm:max-w-72
-        "
+            class="w-auto max-w-75 mx-auto text-5xl text-zinc-700 mb-3 sm:mx-none sm:w-1/2 sm:max-w-72"
           >
             <span class="text-tres-primary">TresJS</span> Playground
           </h1>
-          <p class="text-lg">
-            Testing zone for TresJS/core components
-          </p>
+          <p class="text-lg">Testing zone for TresJS/core components</p>
         </div>
       </div>
-      <div class="text-center sm:text-left sm:grid sm:grid-cols-2 md:grid-cols-3 gap-4">
+      <div
+        class="text-center sm:text-left sm:grid sm:grid-cols-2 md:grid-cols-3 gap-4"
+      >
         <div
           v-for="{ title, routes, icon } in sections"
           :key="title"
-          class="
-          p-4 my-4 leading-normal size-m weight-600 bg-zinc-50 rounded
-          sm:my-0
-          "
+          class="p-4 my-4 leading-normal size-m weight-600 bg-zinc-50 rounded sm:my-0"
         >
-          <div class="inline-block p-2 p-x-3 m-b-3 text-2xl bg-zinc-200 rounded">
+          <div
+            class="inline-block p-2 p-x-3 m-b-3 text-2xl bg-zinc-200 rounded"
+          >
             {{ icon }}
           </div>
           <h2 class="text-sm p-0 m-0 mb-1.5 font-semibold text-zinc-600">
             {{ title }}
           </h2>
-          <div
-            v-for="route in routes"
-            :key="route.name"
-            class="link-wrapper"
-          >
-            <router-link
-              class="no-underline text-zinc-700 visited:text-zinc-400 hover:text-cientos-blue"
-              :to="route.path"
-            >
-              <span>{{ route.name }} </span>
-            </router-link>
+          <div v-if="routes.length">
+            <div v-for="route in routes" :key="route.name" class="link-wrapper">
+              <router-link
+                class="no-underline text-zinc-700 visited:text-zinc-400 hover:text-cientos-blue"
+                :to="route.path"
+              >
+                <span>{{ route.name }} </span>
+              </router-link>
+            </div>
+          </div>
+          <div v-else>
+            (empty)
           </div>
         </div>
       </div>

+ 0 - 0
playground/src/pages/basic/vIf/MyBox.vue → playground/src/pages/issues/717/MyBox.vue


+ 1 - 2
playground/src/pages/basic/vIf/index.vue → playground/src/pages/issues/717/index.vue

@@ -42,10 +42,9 @@ onUnmounted(() => intervalId && clearInterval(intervalId))
         <TresMeshBasicMaterial color="red" />
       </TresMesh>
     </TresMesh>
-    <TresDirectionalLight :position="[0, 2, 4]" :intensity="1.2" cast-shadow />
   </TresCanvas>
   <OverlayInfo>
-    <h1>v-if</h1>
+    <h1>Issue #717: v-if</h1>
     <h2>Setup</h2>
     <p>
       In this scene, there is a Box with a <code>v-if</code>. Its <code>v-if</code> value is toggled on and off.

+ 1 - 1
playground/src/components/DirectiveSubComponent.vue → playground/src/pages/misc/directives/DirectiveSubComponent.vue

@@ -3,5 +3,5 @@ import { vLightHelper } from '@tresjs/core'
 </script>
 
 <template>
-  <TresDirectionalLight v-light-helper :position="[3, 3, 3]" :intensity="1" />
+  <TresDirectionalLight v-light-helper :position="[-1, 1, 0]" :intensity="1" />
 </template>

+ 1 - 1
playground/src/pages/misc/Directives.vue → playground/src/pages/misc/directives/index.vue

@@ -1,8 +1,8 @@
 <script setup lang="ts">
 import { TresCanvas } from '@tresjs/core'
 import { BasicShadowMap, NoToneMapping, SRGBColorSpace } from 'three'
-
 import { OrbitControls } from '@tresjs/cientos'
+import DirectiveSubComponent from './DirectiveSubComponent.vue'
 
 const gl = {
   clearColor: '#82DBC5',

+ 0 - 0
playground/src/components/Text3D.vue → playground/src/pages/misc/text3D/Text3D.vue


+ 1 - 0
playground/src/pages/misc/Text3DDemo.vue → playground/src/pages/misc/text3D/index.vue

@@ -3,6 +3,7 @@ import { TresCanvas } from '@tresjs/core'
 import { BasicShadowMap, NoToneMapping, SRGBColorSpace } from 'three'
 import { OrbitControls } from '@tresjs/cientos'
 import { TresLeches, useControls } from '@tresjs/leches'
+import Text3D from './Text3D.vue'
 
 import '@tresjs/leches/styles'
 

+ 2 - 114
playground/src/router/index.ts

@@ -1,6 +1,5 @@
 import { createRouter, createWebHistory } from 'vue-router'
-import { basicRoutes } from './routes/basic'
-import { advancedRoutes, cameraRoutes, eventsRoutes, miscRoutes, modelsRoutes } from './routes'
+import { allRoutes } from './routes'
 
 const routes = [
   {
@@ -8,118 +7,7 @@ const routes = [
     name: 'Home',
     component: () => import('../pages/index.vue'),
   },
-  ...basicRoutes,
-  ...advancedRoutes,
-  ...eventsRoutes,
-  ...cameraRoutes,
-  ...modelsRoutes,
-  ...miscRoutes,
-/*   {
-    path: '/',
-    name: 'Home',
-    component: () => import('./pages/index.vue'),
-  },
-  {
-    path: '/basic',
-    name: 'Basic',
-    component: () => import('./pages/TheBasic.vue'),
-  },
-  {
-    path: '/lights',
-    name: 'lights',
-    component: () => import('./pages/lights.vue'),
-  },
-  {
-    path: '/groups',
-    name: 'Groups',
-    component: () => import('./pages/TheGroups.vue'),
-  },
-  {
-    path: '/responsiveness',
-    name: 'Responsiveness',
-    component: () => import('./pages/Responsiveness.vue'),
-  },
-  {
-    path: '/conditional',
-    name: 'Conditional',
-    component: () => import('./pages/TheConditional.vue'),
-  },
-  {
-    path: '/multiple',
-    name: 'Multiple',
-    component: () => import('./pages/MultipleCanvas.vue'),
-  },
-  {
-    path: '/cameras/multiple-cameras',
-    name: 'Multiple Cameras',
-    component: () => import('./pages/cameras/MultipleCameras.vue'),
-  },
-  {
-    path: '/cameras/no-camera',
-    name: 'No Camera',
-    component: () => import('./pages/cameras/NoCamera.vue'),
-  },
-  {
-    path: '/cameras/camera',
-    name: 'Camera',
-    component: () => import('./pages/cameras/Cameras.vue'),
-  },
-  {
-    path: '/raycaster/events',
-    name: 'Raycaster',
-    component: () => import('./pages/raycaster/TheEvents.vue'),
-  },
-  {
-    path: '/raycaster/propagation',
-    name: 'Event Propogation',
-    component: () => import('./pages/raycaster/Propagation.vue'),
-  },
-  {
-    path: '/misc/text-3d',
-    name: 'Text3D',
-    component: () => import('./pages/misc/Text3DDemo.vue'),
-  },
-  {
-    path: '/misc/gui-controls',
-    name: 'GUI Controls',
-    component: () => import('./pages/misc/GUI.vue'),
-  },
-  {
-    path: '/misc/particles',
-    name: 'Particles',
-    component: () => import('./pages/misc/TheParticles.vue'),
-  },
-  {
-    path: '/click-blocking-box',
-    name: 'Click Blocking Box',
-    component: () => import('./pages/click-blocking-box.vue'),
-  },
-  {
-    path: '/perf',
-    name: 'Perf',
-    component: () => import('./pages/perf/index.vue'),
-  },
-  {
-    path: '/primitives',
-    name: 'Primitives',
-    component: () => import('./pages/primitives.vue'),
-  },
-  {
-    path: '/rendering-modes',
-    name: 'Rendering Modes',
-    component: () => import('./pages/rendering-modes/index.vue'),
-  },
-  {
-    path: '/on-demand-rendering',
-    name: 'On Demand Rendering',
-    component: () => import('./pages/on-demand-rendering.vue'),
-  },
-  {
-    path: '/empty',
-    name: 'empty',
-    component: () => import('./pages/empty.vue'),
-  },
-   */
+  ...allRoutes,
 ]
 export const router = createRouter({
   history: createWebHistory(),

+ 9 - 4
playground/src/router/routes/advanced.ts

@@ -10,13 +10,18 @@ export const advancedRoutes = [
     component: () => import('../../pages/advanced/manual/index.vue'),
   },
   {
-    path: '/advanced/take-over-loop',
-    name: 'Take Over loop',
-    component: () => import('../../pages/advanced/TakeOverLoop.vue'),
+    path: '/advanced/take-over-render',
+    name: 'Take Over render',
+    component: () => import('../../pages/advanced/takeOverRender/index.vue'),
   },
   {
     path: '/advanced/fbo',
     name: 'FBO',
-    component: () => import('../../pages/advanced/FBO.vue'),
+    component: () => import('../../pages/advanced/fbo/index.vue'),
+  },
+  {
+    path: '/advanced/suspense',
+    name: 'Suspense',
+    component: () => import('../../pages/advanced/suspense/index.vue'),
   },
 ]

+ 0 - 5
playground/src/router/routes/basic.ts

@@ -44,9 +44,4 @@ export const basicRoutes = [
     name: 'Pierced Props',
     component: () => import('../../pages/basic/PiercedProps.vue'),
   },
-  {
-    path: '/basic/v-if',
-    name: 'v-if',
-    component: () => import('../../pages/basic/vIf/index.vue'),
-  },
 ]

+ 1 - 1
playground/src/router/routes/cameras.ts

@@ -12,6 +12,6 @@ export const cameraRoutes = [
   {
     path: '/cameras/multiple-cameras',
     name: 'Multiple Cameras',
-    component: () => import('../../pages/cameras/MultipleCameras.vue'),
+    component: () => import('../../pages/cameras/multipleCameras/index.vue'),
   },
 ]

+ 13 - 0
playground/src/router/routes/index.ts

@@ -4,6 +4,17 @@ import { eventsRoutes } from './events'
 import { basicRoutes } from './basic'
 import { advancedRoutes } from './advanced'
 import { miscRoutes } from './misc'
+import { issuesRoutes } from './issues'
+
+const allRoutes = [
+  ...basicRoutes,
+  ...advancedRoutes,
+  ...eventsRoutes,
+  ...cameraRoutes,
+  ...modelsRoutes,
+  ...miscRoutes,
+  ...issuesRoutes,
+]
 
 export {
   basicRoutes,
@@ -12,4 +23,6 @@ export {
   cameraRoutes,
   modelsRoutes,
   miscRoutes,
+  issuesRoutes,
+  allRoutes,
 }

+ 7 - 0
playground/src/router/routes/issues.ts

@@ -0,0 +1,7 @@
+export const issuesRoutes = [
+  {
+    path: '/issues/717vIf',
+    name: '#717: v-if',
+    component: () => import('../../pages/issues/717/index.vue'),
+  },
+]

+ 2 - 2
playground/src/router/routes/misc.ts

@@ -2,11 +2,11 @@ export const miscRoutes = [
   {
     path: '/misc',
     name: 'Text 3D',
-    component: () => import('../../pages/misc/Text3DDemo.vue'),
+    component: () => import('../../pages/misc/text3D/index.vue'),
   },
   {
     path: '/misc/directives',
     name: 'Directives',
-    component: () => import('../../pages/misc/Directives.vue'),
+    component: () => import('../../pages/misc/directives/index.vue'),
   },
 ]