1
0
Эх сурвалжийг харах

Merge pull request #147 from Tresjs/feature/86-explore-vue-custom-render-api-v2

[v2] - feat(core): custom renderer
Alvaro Saburido 2 жил өмнө
parent
commit
0c5deaf337
63 өөрчлөгдсөн 906 нэмэгдсэн , 1391 устгасан
  1. 1 1
      docs/examples/text-3d.md
  2. 1 1
      package.json
  3. 2 2
      packages/cientos/package.json
  4. 0 1
      packages/cientos/src/core/OrbitControls.vue
  5. 8 2
      packages/cientos/src/core/useCientos.ts
  6. 1 1
      packages/cientos/src/core/usePamCameraMouse/index.ts
  7. 0 400
      packages/tres/build/config.gypi
  8. 0 1
      packages/tres/build/node_gyp_bins/python3
  9. 7 7
      packages/tres/package.json
  10. 2 8
      packages/tres/src/App.vue
  11. 0 133
      packages/tres/src/components/Shapes.vue
  12. 0 30
      packages/tres/src/components/TestSphere.vue
  13. 125 0
      packages/tres/src/components/TresCanvas.ts
  14. 7 0
      packages/tres/src/composables/index.ts
  15. 10 7
      packages/tres/src/composables/useCamera/index.ts
  16. 0 0
      packages/tres/src/composables/useCamera/useCamera.test.ts
  17. 0 0
      packages/tres/src/composables/useLoader/index.ts
  18. 0 0
      packages/tres/src/composables/useLoader/useLoader.test.ts
  19. 4 8
      packages/tres/src/composables/useRaycaster/index.ts
  20. 0 0
      packages/tres/src/composables/useRaycaster/useRaycaster.test.ts
  21. 0 0
      packages/tres/src/composables/useRenderLoop/index.ts
  22. 0 0
      packages/tres/src/composables/useRenderer/const.ts
  23. 1 1
      packages/tres/src/composables/useRenderer/index.ts
  24. 0 0
      packages/tres/src/composables/useTexture/index.ts
  25. 0 0
      packages/tres/src/composables/useTexture/useTexture.test.ts
  26. 1 1
      packages/tres/src/composables/useTres/index.ts
  27. 0 0
      packages/tres/src/composables/useTres/useTres.test.ts
  28. 15 0
      packages/tres/src/core/catalogue.test.ts
  29. 9 0
      packages/tres/src/core/catalogue.ts
  30. 0 10
      packages/tres/src/core/index.ts
  31. 175 0
      packages/tres/src/core/nodeOps.ts
  32. 174 0
      packages/tres/src/core/nodeOpts.test.ts
  33. 19 0
      packages/tres/src/core/renderer.ts
  34. 0 69
      packages/tres/src/core/useCatalogue/index.ts
  35. 0 28
      packages/tres/src/core/useCatalogue/useCatalogue.test.ts
  36. 0 348
      packages/tres/src/core/useInstanceCreator/index.ts
  37. 0 27
      packages/tres/src/core/useInstanceCreator/useInstanceCreator.test.ts
  38. 0 103
      packages/tres/src/core/useRenderer/component.ts
  39. 0 42
      packages/tres/src/core/useScene/component.ts
  40. 0 16
      packages/tres/src/core/useScene/index.ts
  41. 0 10
      packages/tres/src/core/useScene/useScene.test.ts
  42. 28 0
      packages/tres/src/demos/AkuAku.vue
  43. 0 0
      packages/tres/src/demos/AnimatedModel.vue
  44. 18 19
      packages/tres/src/demos/FBXModels.vue
  45. 0 0
      packages/tres/src/demos/Responsiveness.vue
  46. 133 0
      packages/tres/src/demos/Shapes.vue
  47. 32 0
      packages/tres/src/demos/TestSphere.vue
  48. 3 3
      packages/tres/src/demos/Text3D.vue
  49. 0 0
      packages/tres/src/demos/TheBasic.vue
  50. 0 0
      packages/tres/src/demos/TheEnvironment.vue
  51. 0 0
      packages/tres/src/demos/TheEvents.vue
  52. 0 0
      packages/tres/src/demos/TheExperience.vue
  53. 11 14
      packages/tres/src/demos/TheGizmos.vue
  54. 1 1
      packages/tres/src/demos/TheGroups.vue
  55. 0 0
      packages/tres/src/demos/TheParticles.vue
  56. 0 0
      packages/tres/src/demos/TheSmallExperience.vue
  57. 0 0
      packages/tres/src/demos/VectorSetProps.vue
  58. 6 25
      packages/tres/src/index.ts
  59. 3 2
      packages/tres/src/main.ts
  60. 4 0
      packages/tres/src/types/index.ts
  61. 26 0
      packages/tres/src/utils/index.ts
  62. 5 0
      packages/tres/vite.config.ts
  63. 74 70
      pnpm-lock.yaml

+ 1 - 1
docs/examples/text-3d.md

@@ -95,7 +95,7 @@ So the final code would be something like this:
 <script setup lang="ts">
 import { TextGeometry } from 'three/examples/jsm/geometries/TextGeometry'
 import { FontLoader } from 'three/examples/jsm/loaders/FontLoader'
-import { useCatalogue, useTexture } from '/@/core'
+import { useCatalogue, useTexture } from '/@/composables'
 const { extend } = useCatalogue()
 
 extend({ TextGeometry: TextGeometry })

+ 1 - 1
package.json

@@ -52,7 +52,7 @@
     "@changesets/cli": "^2.25.2",
     "@stackblitz/sdk": "^1.8.1",
     "@tresjs/cientos": "workspace:^1.8.0",
-    "@tresjs/core": "workspace:^1.8.1",
+    "@tresjs/core": "workspace:^2.0.0",
     "@typescript-eslint/eslint-plugin": "^5.42.0",
     "@typescript-eslint/parser": "^5.42.0",
     "conventional-changelog-cli": "^2.2.2",

+ 2 - 2
packages/cientos/package.json

@@ -37,7 +37,7 @@
     "changelog": "conventional-changelog -p angular -i CHANGELOG.md -s"
   },
   "peerDependencies": {
-    "@tresjs/core": "workspace:^1.8.1",
+    "@tresjs/core": "workspace:^2.0.0",
     "three": "latest",
     "vue": "^3.2.47"
   },
@@ -55,7 +55,7 @@
     "vite-plugin-dts": "2.0.0-beta.1"
   },
   "dependencies": {
-    "@tresjs/core": "workspace:^1.8.1",
+    "@tresjs/core": "workspace:^2.0.0",
     "three-stdlib": "^2.21.8"
   }
 }

+ 0 - 1
packages/cientos/src/core/OrbitControls.vue

@@ -74,6 +74,5 @@ watch(controls, value => {
     v-if="state.camera && state.renderer"
     ref="controls"
     :args="[unref(state.camera) || camera, state.renderer?.domElement || domElement]"
-    :enabling-dampling="enableDamping"
   />
 </template>

+ 8 - 2
packages/cientos/src/core/useCientos.ts

@@ -1,5 +1,5 @@
 import { useTres } from '@tresjs/core'
-import { inject } from 'vue'
+import { inject, watch } from 'vue'
 
 /**
  * Allows to use and extend the state of the core package.
@@ -8,13 +8,19 @@ import { inject } from 'vue'
  * @return {*}
  */
 export function useCientos() {
+  const { state, setState } = inject('useTres', useTres())
   const extend =
     inject<(objects: any) => void>('extend') ||
     (() => {
       console.warn('No extend function provided')
     })
 
-  const { state, setState } = inject('useTres', useTres())
+  watch(
+    () => state,
+    () => {
+      console.log('cientos state changed', state)
+    },
+  )
   return {
     state,
     setState,

+ 1 - 1
packages/cientos/src/core/usePamCameraMouse/index.ts

@@ -1,7 +1,7 @@
 import { watchEffect, computed } from 'vue'
 import { Camera } from 'three'
 import { useWindowSize, useMouse } from '@vueuse/core'
-import { useLogger } from '/@/composables/useLogger'
+import { useLogger } from '@tresjs/core'
 
 export function usePamCameraMouse(disabled = false, factor = 5, camera: Camera | undefined) {
   const { x, y } = useMouse()

+ 0 - 400
packages/tres/build/config.gypi

@@ -1,400 +0,0 @@
-# Do not edit. File was generated by node-gyp's "configure" step
-{
-  "target_defaults": {
-    "cflags": [],
-    "default_configuration": "Release",
-    "defines": [],
-    "include_dirs": [],
-    "libraries": [],
-    "msvs_configuration_platform": "ARM64",
-    "xcode_configuration_platform": "arm64"
-  },
-  "variables": {
-    "arm_fpu": "neon",
-    "asan": 0,
-    "coverage": "false",
-    "dcheck_always_on": 0,
-    "debug_nghttp2": "false",
-    "debug_node": "false",
-    "enable_lto": "false",
-    "enable_pgo_generate": "false",
-    "enable_pgo_use": "false",
-    "error_on_warn": "false",
-    "force_dynamic_crt": 0,
-    "host_arch": "arm64",
-    "icu_data_in": "../../deps/icu-tmp/icudt72l.dat",
-    "icu_endianness": "l",
-    "icu_gyp_path": "tools/icu/icu-generic.gyp",
-    "icu_path": "deps/icu-small",
-    "icu_small": "false",
-    "icu_ver_major": "72",
-    "is_debug": 0,
-    "libdir": "lib",
-    "llvm_version": "12.0",
-    "napi_build_version": "8",
-    "node_builtin_shareable_builtins": [
-      "deps/cjs-module-lexer/lexer.js",
-      "deps/cjs-module-lexer/dist/lexer.js",
-      "deps/undici/undici.js"
-    ],
-    "node_byteorder": "little",
-    "node_debug_lib": "false",
-    "node_enable_d8": "false",
-    "node_enable_v8_vtunejit": "false",
-    "node_fipsinstall": "false",
-    "node_install_corepack": "true",
-    "node_install_npm": "true",
-    "node_library_files": [
-      "lib/_http_agent.js",
-      "lib/_http_client.js",
-      "lib/_http_common.js",
-      "lib/_http_incoming.js",
-      "lib/_http_outgoing.js",
-      "lib/_http_server.js",
-      "lib/_stream_duplex.js",
-      "lib/_stream_passthrough.js",
-      "lib/_stream_readable.js",
-      "lib/_stream_transform.js",
-      "lib/_stream_wrap.js",
-      "lib/_stream_writable.js",
-      "lib/_tls_common.js",
-      "lib/_tls_wrap.js",
-      "lib/assert.js",
-      "lib/assert/strict.js",
-      "lib/async_hooks.js",
-      "lib/buffer.js",
-      "lib/child_process.js",
-      "lib/cluster.js",
-      "lib/console.js",
-      "lib/constants.js",
-      "lib/crypto.js",
-      "lib/dgram.js",
-      "lib/diagnostics_channel.js",
-      "lib/dns.js",
-      "lib/dns/promises.js",
-      "lib/domain.js",
-      "lib/events.js",
-      "lib/fs.js",
-      "lib/fs/promises.js",
-      "lib/http.js",
-      "lib/http2.js",
-      "lib/https.js",
-      "lib/inspector.js",
-      "lib/internal/abort_controller.js",
-      "lib/internal/assert.js",
-      "lib/internal/assert/assertion_error.js",
-      "lib/internal/assert/calltracker.js",
-      "lib/internal/async_hooks.js",
-      "lib/internal/blob.js",
-      "lib/internal/blocklist.js",
-      "lib/internal/bootstrap/browser.js",
-      "lib/internal/bootstrap/loaders.js",
-      "lib/internal/bootstrap/node.js",
-      "lib/internal/bootstrap/switches/does_not_own_process_state.js",
-      "lib/internal/bootstrap/switches/does_own_process_state.js",
-      "lib/internal/bootstrap/switches/is_main_thread.js",
-      "lib/internal/bootstrap/switches/is_not_main_thread.js",
-      "lib/internal/buffer.js",
-      "lib/internal/child_process.js",
-      "lib/internal/child_process/serialization.js",
-      "lib/internal/cli_table.js",
-      "lib/internal/cluster/child.js",
-      "lib/internal/cluster/primary.js",
-      "lib/internal/cluster/round_robin_handle.js",
-      "lib/internal/cluster/shared_handle.js",
-      "lib/internal/cluster/utils.js",
-      "lib/internal/cluster/worker.js",
-      "lib/internal/console/constructor.js",
-      "lib/internal/console/global.js",
-      "lib/internal/constants.js",
-      "lib/internal/crypto/aes.js",
-      "lib/internal/crypto/certificate.js",
-      "lib/internal/crypto/cfrg.js",
-      "lib/internal/crypto/cipher.js",
-      "lib/internal/crypto/diffiehellman.js",
-      "lib/internal/crypto/ec.js",
-      "lib/internal/crypto/hash.js",
-      "lib/internal/crypto/hashnames.js",
-      "lib/internal/crypto/hkdf.js",
-      "lib/internal/crypto/keygen.js",
-      "lib/internal/crypto/keys.js",
-      "lib/internal/crypto/mac.js",
-      "lib/internal/crypto/pbkdf2.js",
-      "lib/internal/crypto/random.js",
-      "lib/internal/crypto/rsa.js",
-      "lib/internal/crypto/scrypt.js",
-      "lib/internal/crypto/sig.js",
-      "lib/internal/crypto/util.js",
-      "lib/internal/crypto/webcrypto.js",
-      "lib/internal/crypto/x509.js",
-      "lib/internal/debugger/inspect.js",
-      "lib/internal/debugger/inspect_client.js",
-      "lib/internal/debugger/inspect_repl.js",
-      "lib/internal/dgram.js",
-      "lib/internal/dns/callback_resolver.js",
-      "lib/internal/dns/promises.js",
-      "lib/internal/dns/utils.js",
-      "lib/internal/dtrace.js",
-      "lib/internal/encoding.js",
-      "lib/internal/error_serdes.js",
-      "lib/internal/errors.js",
-      "lib/internal/event_target.js",
-      "lib/internal/file.js",
-      "lib/internal/fixed_queue.js",
-      "lib/internal/freelist.js",
-      "lib/internal/freeze_intrinsics.js",
-      "lib/internal/fs/cp/cp-sync.js",
-      "lib/internal/fs/cp/cp.js",
-      "lib/internal/fs/dir.js",
-      "lib/internal/fs/promises.js",
-      "lib/internal/fs/read_file_context.js",
-      "lib/internal/fs/recursive_watch.js",
-      "lib/internal/fs/rimraf.js",
-      "lib/internal/fs/streams.js",
-      "lib/internal/fs/sync_write_stream.js",
-      "lib/internal/fs/utils.js",
-      "lib/internal/fs/watchers.js",
-      "lib/internal/heap_utils.js",
-      "lib/internal/histogram.js",
-      "lib/internal/http.js",
-      "lib/internal/http2/compat.js",
-      "lib/internal/http2/core.js",
-      "lib/internal/http2/util.js",
-      "lib/internal/idna.js",
-      "lib/internal/inspector_async_hook.js",
-      "lib/internal/js_stream_socket.js",
-      "lib/internal/legacy/processbinding.js",
-      "lib/internal/linkedlist.js",
-      "lib/internal/main/check_syntax.js",
-      "lib/internal/main/environment.js",
-      "lib/internal/main/eval_stdin.js",
-      "lib/internal/main/eval_string.js",
-      "lib/internal/main/inspect.js",
-      "lib/internal/main/mksnapshot.js",
-      "lib/internal/main/print_help.js",
-      "lib/internal/main/prof_process.js",
-      "lib/internal/main/repl.js",
-      "lib/internal/main/run_main_module.js",
-      "lib/internal/main/test_runner.js",
-      "lib/internal/main/watch_mode.js",
-      "lib/internal/main/worker_thread.js",
-      "lib/internal/mime.js",
-      "lib/internal/modules/cjs/helpers.js",
-      "lib/internal/modules/cjs/loader.js",
-      "lib/internal/modules/esm/assert.js",
-      "lib/internal/modules/esm/create_dynamic_module.js",
-      "lib/internal/modules/esm/fetch_module.js",
-      "lib/internal/modules/esm/formats.js",
-      "lib/internal/modules/esm/get_format.js",
-      "lib/internal/modules/esm/handle_process_exit.js",
-      "lib/internal/modules/esm/initialize_import_meta.js",
-      "lib/internal/modules/esm/load.js",
-      "lib/internal/modules/esm/loader.js",
-      "lib/internal/modules/esm/module_job.js",
-      "lib/internal/modules/esm/module_map.js",
-      "lib/internal/modules/esm/package_config.js",
-      "lib/internal/modules/esm/resolve.js",
-      "lib/internal/modules/esm/translators.js",
-      "lib/internal/modules/package_json_reader.js",
-      "lib/internal/modules/run_main.js",
-      "lib/internal/net.js",
-      "lib/internal/options.js",
-      "lib/internal/per_context/domexception.js",
-      "lib/internal/per_context/messageport.js",
-      "lib/internal/per_context/primordials.js",
-      "lib/internal/perf/event_loop_delay.js",
-      "lib/internal/perf/event_loop_utilization.js",
-      "lib/internal/perf/nodetiming.js",
-      "lib/internal/perf/observe.js",
-      "lib/internal/perf/performance.js",
-      "lib/internal/perf/performance_entry.js",
-      "lib/internal/perf/resource_timing.js",
-      "lib/internal/perf/timerify.js",
-      "lib/internal/perf/usertiming.js",
-      "lib/internal/perf/utils.js",
-      "lib/internal/policy/manifest.js",
-      "lib/internal/policy/sri.js",
-      "lib/internal/priority_queue.js",
-      "lib/internal/process/esm_loader.js",
-      "lib/internal/process/execution.js",
-      "lib/internal/process/per_thread.js",
-      "lib/internal/process/policy.js",
-      "lib/internal/process/pre_execution.js",
-      "lib/internal/process/promises.js",
-      "lib/internal/process/report.js",
-      "lib/internal/process/signal.js",
-      "lib/internal/process/task_queues.js",
-      "lib/internal/process/warning.js",
-      "lib/internal/process/worker_thread_only.js",
-      "lib/internal/promise_hooks.js",
-      "lib/internal/querystring.js",
-      "lib/internal/readline/callbacks.js",
-      "lib/internal/readline/emitKeypressEvents.js",
-      "lib/internal/readline/interface.js",
-      "lib/internal/readline/promises.js",
-      "lib/internal/readline/utils.js",
-      "lib/internal/repl.js",
-      "lib/internal/repl/await.js",
-      "lib/internal/repl/history.js",
-      "lib/internal/repl/utils.js",
-      "lib/internal/socket_list.js",
-      "lib/internal/socketaddress.js",
-      "lib/internal/source_map/prepare_stack_trace.js",
-      "lib/internal/source_map/source_map.js",
-      "lib/internal/source_map/source_map_cache.js",
-      "lib/internal/stream_base_commons.js",
-      "lib/internal/streams/add-abort-signal.js",
-      "lib/internal/streams/buffer_list.js",
-      "lib/internal/streams/compose.js",
-      "lib/internal/streams/destroy.js",
-      "lib/internal/streams/duplex.js",
-      "lib/internal/streams/duplexify.js",
-      "lib/internal/streams/end-of-stream.js",
-      "lib/internal/streams/from.js",
-      "lib/internal/streams/lazy_transform.js",
-      "lib/internal/streams/legacy.js",
-      "lib/internal/streams/operators.js",
-      "lib/internal/streams/passthrough.js",
-      "lib/internal/streams/pipeline.js",
-      "lib/internal/streams/readable.js",
-      "lib/internal/streams/state.js",
-      "lib/internal/streams/transform.js",
-      "lib/internal/streams/utils.js",
-      "lib/internal/streams/writable.js",
-      "lib/internal/structured_clone.js",
-      "lib/internal/test/binding.js",
-      "lib/internal/test/transfer.js",
-      "lib/internal/test_runner/harness.js",
-      "lib/internal/test_runner/mock.js",
-      "lib/internal/test_runner/runner.js",
-      "lib/internal/test_runner/tap_checker.js",
-      "lib/internal/test_runner/tap_lexer.js",
-      "lib/internal/test_runner/tap_parser.js",
-      "lib/internal/test_runner/tap_stream.js",
-      "lib/internal/test_runner/test.js",
-      "lib/internal/test_runner/utils.js",
-      "lib/internal/test_runner/yaml_parser.js",
-      "lib/internal/timers.js",
-      "lib/internal/tls/secure-context.js",
-      "lib/internal/tls/secure-pair.js",
-      "lib/internal/trace_events_async_hooks.js",
-      "lib/internal/tty.js",
-      "lib/internal/url.js",
-      "lib/internal/util.js",
-      "lib/internal/util/colors.js",
-      "lib/internal/util/comparisons.js",
-      "lib/internal/util/debuglog.js",
-      "lib/internal/util/inspect.js",
-      "lib/internal/util/inspector.js",
-      "lib/internal/util/iterable_weak_map.js",
-      "lib/internal/util/parse_args/parse_args.js",
-      "lib/internal/util/parse_args/utils.js",
-      "lib/internal/util/types.js",
-      "lib/internal/v8/startup_snapshot.js",
-      "lib/internal/v8_prof_polyfill.js",
-      "lib/internal/v8_prof_processor.js",
-      "lib/internal/validators.js",
-      "lib/internal/vm.js",
-      "lib/internal/vm/module.js",
-      "lib/internal/wasm_web_api.js",
-      "lib/internal/watch_mode/files_watcher.js",
-      "lib/internal/watchdog.js",
-      "lib/internal/webstreams/adapters.js",
-      "lib/internal/webstreams/compression.js",
-      "lib/internal/webstreams/encoding.js",
-      "lib/internal/webstreams/queuingstrategies.js",
-      "lib/internal/webstreams/readablestream.js",
-      "lib/internal/webstreams/transfer.js",
-      "lib/internal/webstreams/transformstream.js",
-      "lib/internal/webstreams/util.js",
-      "lib/internal/webstreams/writablestream.js",
-      "lib/internal/worker.js",
-      "lib/internal/worker/io.js",
-      "lib/internal/worker/js_transferable.js",
-      "lib/module.js",
-      "lib/net.js",
-      "lib/os.js",
-      "lib/path.js",
-      "lib/path/posix.js",
-      "lib/path/win32.js",
-      "lib/perf_hooks.js",
-      "lib/process.js",
-      "lib/punycode.js",
-      "lib/querystring.js",
-      "lib/readline.js",
-      "lib/readline/promises.js",
-      "lib/repl.js",
-      "lib/stream.js",
-      "lib/stream/consumers.js",
-      "lib/stream/promises.js",
-      "lib/stream/web.js",
-      "lib/string_decoder.js",
-      "lib/sys.js",
-      "lib/test.js",
-      "lib/timers.js",
-      "lib/timers/promises.js",
-      "lib/tls.js",
-      "lib/trace_events.js",
-      "lib/tty.js",
-      "lib/url.js",
-      "lib/util.js",
-      "lib/util/types.js",
-      "lib/v8.js",
-      "lib/vm.js",
-      "lib/wasi.js",
-      "lib/worker_threads.js",
-      "lib/zlib.js"
-    ],
-    "node_module_version": 108,
-    "node_no_browser_globals": "false",
-    "node_prefix": "/",
-    "node_release_urlbase": "https://nodejs.org/download/release/",
-    "node_shared": "false",
-    "node_shared_brotli": "false",
-    "node_shared_cares": "false",
-    "node_shared_http_parser": "false",
-    "node_shared_libuv": "false",
-    "node_shared_nghttp2": "false",
-    "node_shared_nghttp3": "false",
-    "node_shared_ngtcp2": "false",
-    "node_shared_openssl": "false",
-    "node_shared_zlib": "false",
-    "node_tag": "",
-    "node_target_type": "executable",
-    "node_use_bundled_v8": "true",
-    "node_use_dtrace": "true",
-    "node_use_etw": "false",
-    "node_use_node_code_cache": "true",
-    "node_use_node_snapshot": "true",
-    "node_use_openssl": "true",
-    "node_use_v8_platform": "true",
-    "node_with_ltcg": "false",
-    "node_without_node_options": "false",
-    "openssl_is_fips": "false",
-    "openssl_quic": "true",
-    "ossfuzz": "false",
-    "shlib_suffix": "108.dylib",
-    "target_arch": "arm64",
-    "v8_enable_31bit_smis_on_64bit_arch": 0,
-    "v8_enable_gdbjit": 0,
-    "v8_enable_hugepage": 0,
-    "v8_enable_i18n_support": 1,
-    "v8_enable_inspector": 1,
-    "v8_enable_javascript_promise_hooks": 1,
-    "v8_enable_lite_mode": 0,
-    "v8_enable_object_print": 1,
-    "v8_enable_pointer_compression": 0,
-    "v8_enable_shared_ro_heap": 1,
-    "v8_enable_webassembly": 1,
-    "v8_no_strict_aliasing": 1,
-    "v8_optimized_debug": 1,
-    "v8_promise_internal_field_count": 1,
-    "v8_random_seed": 0,
-    "v8_trace_maps": 0,
-    "v8_use_siphash": 1,
-    "want_separate_host_toolset": 0,
-    "xcode_version": "12.0",
-    "nodedir": "/Users/alvarosabu/Library/Caches/node-gyp/18.14.1",
-    "standalone_static_library": 1
-  }
-}

+ 0 - 1
packages/tres/build/node_gyp_bins/python3

@@ -1 +0,0 @@
-/Library/Developer/CommandLineTools/usr/bin/python3

+ 7 - 7
packages/tres/package.json

@@ -1,7 +1,7 @@
 {
   "name": "@tresjs/core",
   "description": "Declarative ThreeJS using Vue Components",
-  "version": "1.8.1",
+  "version": "2.0.0",
   "type": "module",
   "author": "Alvaro Saburido <hola@alvarosaburido.dev> (https://github.com/alvarosabu/)",
   "files": [
@@ -56,9 +56,9 @@
     "@tresjs/cientos": "workspace:^1.8.0",
     "@types/three": "latest",
     "@vitejs/plugin-vue": "^4.0.0",
-    "@vitest/coverage-c8": "^0.28.5",
-    "@vitest/ui": "^0.28.5",
-    "@vue/test-utils": "^2.3.0",
+    "@vitest/coverage-c8": "^0.29.2",
+    "@vitest/ui": "^0.29.2",
+    "@vue/test-utils": "^2.3.1",
     "happy-dom": "^8.7.1",
     "jsdom": "^21.1.0",
     "kolorist": "^1.7.0",
@@ -68,11 +68,11 @@
     "three": "latest",
     "vite": "^4.1.4",
     "vite-plugin-banner": "^0.7.0",
-    "vite-plugin-dts": "2.0.0-beta.1",
+    "vite-plugin-dts": "2.1.0",
     "vite-plugin-glsl": "^1.1.2",
-    "vite-plugin-inspect": "^0.7.15",
+    "vite-plugin-inspect": "^0.7.16",
     "vite-plugin-require-transform": "^1.0.9",
-    "vitest": "^0.28.5",
+    "vitest": "^0.29.2",
     "vue-demi": "^0.13.11"
   }
 }

+ 2 - 8
packages/tres/src/App.vue

@@ -1,15 +1,10 @@
 <script setup lang="ts">
-import { useTweakPane } from '@tresjs/cientos'
-import Shapes from '/@/components/Shapes.vue'
+import Shapes from './demos/Shapes.vue'
 // import TheEvents from '/@/components/TheEvents.vue'
-
-useTweakPane()
 </script>
 
 <template>
-  <Suspense>
-    <Shapes />
-  </Suspense>
+  <Shapes />
 </template>
 
 <style>
@@ -23,6 +18,5 @@ body {
 #app {
   height: 100%;
   width: 100%;
-  background-color: #000;
 }
 </style>

+ 0 - 133
packages/tres/src/components/Shapes.vue

@@ -1,133 +0,0 @@
-<script setup lang="ts">
-import { BasicShadowMap, CubicBezierCurve3, DoubleSide, NoToneMapping, sRGBEncoding, Vector3 } from 'three'
-import { reactive, shallowRef, watch } from 'vue'
-import {
-  Plane,
-  Tube,
-  Box,
-  Sphere,
-  Torus,
-  Ring,
-  TorusKnot,
-  Tetrahedron,
-  Icosahedron,
-  Octahedron,
-  Dodecahedron,
-  Circle,
-  Cone,
-  OrbitControls,
-} from '../../../cientos/src/'
-
-const state = reactive({
-  clearColor: '#82DBC5',
-  shadows: true,
-  alpha: false,
-  physicallyCorrectLights: true,
-  shadowMapType: BasicShadowMap,
-  outputEncoding: sRGBEncoding,
-  toneMapping: NoToneMapping,
-})
-
-const planeRef = shallowRef()
-const boxRef = shallowRef()
-const torusRef = shallowRef()
-const torusKnotRef = shallowRef()
-const circleRef = shallowRef()
-const tubeRef = shallowRef()
-const ringRef = shallowRef()
-const tetrahedronRef = shallowRef()
-const icosahedronRef = shallowRef()
-const octahedronRef = shallowRef()
-const dodecahedronRef = shallowRef()
-
-watch(planeRef, plane => {
-  console.log('plane', plane.value.position)
-})
-watch(boxRef, box => {
-  console.log('box', box.value.position)
-})
-watch(torusRef, torus => {
-  console.log('torus', torus.value.position)
-})
-watch(torusKnotRef, torusKnot => {
-  console.log('torusKnot', torusKnot.value.position)
-})
-watch(circleRef, circle => {
-  console.log('circle', circle.value.position)
-})
-watch(tubeRef, tube => {
-  console.log('tube', tube.value.position)
-})
-watch(ringRef, ring => {
-  console.log('ring', ring.value.position)
-})
-watch(tetrahedronRef, tetrahedron => {
-  console.log('tetrahedron', tetrahedron.value.position)
-})
-watch(icosahedronRef, icosahedron => {
-  console.log('icosahedron', icosahedron.value.position)
-})
-watch(octahedronRef, octahedron => {
-  console.log('octahedron', octahedron.value.position)
-})
-watch(dodecahedronRef, dodecahedron => {
-  console.log('dodecahedron', dodecahedron.value.position)
-})
-
-const tubePath = new CubicBezierCurve3(
-  new Vector3(-1, 0, 0),
-  new Vector3(-0.5, -1, 0),
-  new Vector3(0.5, 1, 0),
-  new Vector3(1, 0, 0),
-)
-</script>
-
-<template>
-  <TresCanvas v-bind="state">
-    <TresPerspectiveCamera :position="[5, 5, 5]" :fov="75" :aspect="1" :near="0.1" :far="1000" />
-    <OrbitControls />
-    <TresScene>
-      <TresAmbientLight :color="0xffffff" :intensity="1" />
-      <TresDirectionalLight :position="[0, 8, 4]" :intensity="0.7" cast-shadow />
-      <Plane ref="planeRef" :args="[12, 8]" :position="[-2, 4, 0]" receive-shadow>
-        <TresMeshToonMaterial color="teal" />
-      </Plane>
-      <Box ref="boxRef" :arg0s="[1, 1, 1]" :position="[0, 6, 0]" cast-shadow>
-        <TresMeshToonMaterial color="orange" />
-      </Box>
-      <Sphere ref="sphereRef" :args="[1, 32, 16]" :position="[2, 6, 0]" cast-shadow>
-        <TresMeshToonMaterial color="pink" />
-      </Sphere>
-      <Torus ref="torusRef" :args="[0.75, 0.4, 16, 80]" :position="[-2, 6, 0]" cast-shadow>
-        <TresMeshToonMaterial color="cyan" />
-      </Torus>
-      <TorusKnot ref="torusKnotRef" :args="[0.6, 0.2, 64, 8]" :position="[-2, 6, 2]" cast-shadow>
-        <TresMeshToonMaterial color="lime" />
-      </TorusKnot>
-      <Circle ref="circleRef" :args="[0.9, 32]" :position="[0, 6, 2]" :rotation="[Math.PI, 0, 0]" cast-shadow>
-        <TresMeshToonMaterial color="lightsalmon" :side="DoubleSide" />
-      </Circle>
-      <Cone ref="coneRef" :args="[1, 1, 6]" :position="[2, 6, 2]" :rotation="[Math.PI, 0, 0]" cast-shadow>
-        <TresMeshToonMaterial color="slateblue" />
-      </Cone>
-      <Tube ref="tubeRef" :args="[tubePath, 20, 0.2, 8, false]" :position="[2, 6, -2]" cast-shadow>
-        <TresMeshToonMaterial color="lightblue" />
-      </Tube>
-      <Ring ref="ringRef" :args="[0.5, 1, 32]" :position="[0, 6, -2]" :rotation="[Math.PI, 0, 0]" cast-shadow>
-        <TresMeshToonMaterial color="purple" :side="DoubleSide" />
-      </Ring>
-      <Tetrahedron ref="tetrahedronRef" :args="[1, 0]" :position="[-2, 6, -2]" cast-shadow>
-        <TresMeshToonMaterial color="yellow" />
-      </Tetrahedron>
-      <Icosahedron ref="icosahedronRef" :args="[1, 0]" :position="[-4, 6, -2]" cast-shadow>
-        <TresMeshToonMaterial color="red" />
-      </Icosahedron>
-      <Octahedron ref="octahedronRef" :args="[1, 0]" :position="[-4, 6, 0]" cast-shadow>
-        <TresMeshToonMaterial color="greenyellow" />
-      </Octahedron>
-      <Dodecahedron ref="dodecahedronRef" :args="[1, 0]" :position="[-4, 6, 2]" cast-shadow>
-        <TresMeshToonMaterial color="deeppink" />
-      </Dodecahedron>
-    </TresScene>
-  </TresCanvas>
-</template>

+ 0 - 30
packages/tres/src/components/TestSphere.vue

@@ -1,30 +0,0 @@
-<script setup lang="ts">
-import { Ref, ref } from 'vue'
-import { useRenderLoop, useTexture } from '/@/core/'
-import { TresInstance } from '../types'
-
-const sphereRef: Ref<TresInstance | null> = ref(null)
-
-const { onLoop, resume } = useRenderLoop()
-resume()
-onLoop(({ elapsed }) => {
-  if (sphereRef.value) {
-    sphereRef.value.position.y = Math.sin(elapsed * 0.2) * 2.0
-  }
-})
-
-/* const texture = await useTexture(['/textures/stylized-leaves-material/Stylized_Leaves_002_basecolor.jpg']) */
-const pbrTexture = await useTexture({
-  map: '/textures/stylized-leaves-material/Stylized_Leaves_002_basecolor.jpg',
-  displacementMap: '/textures/stylized-leaves-material/Stylized_Leaves_002_height.png',
-  roughnessMap: '/textures/stylized-leaves-material/Stylized_Leaves_002_roughness.jpg',
-  normalMap: '/textures/stylized-leaves-material/Stylized_Leaves_002_normal.jpg',
-  ambientOcclusion: '/textures/stylized-leaves-material/Stylized_Leaves_002_ambientOcclusion.jpg',
-})
-</script>
-<template>
-  <TresMesh ref="sphereRef" :position="[-2, 2, 2]" :scale="1" cast-shadow>
-    <TresSphereGeometry :args="[1, 500, 500]" />
-    <TresMeshStandardMaterial v-bind="pbrTexture" />
-  </TresMesh>
-</template>

+ 125 - 0
packages/tres/src/components/TresCanvas.ts

@@ -0,0 +1,125 @@
+import { defineComponent, h, PropType, ref, watch } from 'vue'
+import * as THREE from 'three'
+import { ShadowMapType, TextureEncoding, ToneMapping } from 'three'
+import { createTres } from '/@/core/renderer'
+import { useLogger } from '/@/composables'
+import { useCamera, useRenderer, useRenderLoop, useRaycaster, useTres } from '/@/composables'
+import { TresObject } from '../types'
+import { extend } from '../core/catalogue'
+import { RendererPresetsType } from '../composables/useRenderer/const'
+
+export interface TresCanvasProps {
+  shadows?: boolean
+  shadowMapType?: ShadowMapType
+  physicallyCorrectLights?: boolean
+  useLegacyLights?: boolean
+  outputEncoding?: TextureEncoding
+  toneMapping?: ToneMapping
+  toneMappingExposure?: number
+  context?: WebGLRenderingContext
+  powerPreference?: 'high-performance' | 'low-power' | 'default'
+  preserveDrawingBuffer?: boolean
+  clearColor?: string
+  windowSize?: boolean
+  preset?: RendererPresetsType
+}
+/**
+ * Vue component for rendering a Tres component.
+ */
+
+const { logWarning } = useLogger()
+
+export const TresCanvas = defineComponent<TresCanvasProps>({
+  name: 'TresCanvas',
+  props: [
+    'shadows',
+    'shadowMapType',
+    'physicallyCorrectLights',
+    'useLegacyLights',
+    'outputEncoding',
+    'toneMapping',
+    'toneMappingExposure',
+    'context',
+    'powerPreference',
+    'preserveDrawingBuffer',
+    'clearColor',
+    'windowSize',
+    'preset',
+  ] as unknown as undefined,
+  setup(props, { slots, expose }) {
+    if (props.physicallyCorrectLights === true) {
+      logWarning('physicallyCorrectLights is deprecated, useLegacyLights is now false by default')
+    }
+    const container = ref<HTMLElement>()
+    const canvas = ref<HTMLCanvasElement>()
+    const scene = new THREE.Scene()
+
+    watch(canvas, () => {
+      const { renderer } = useRenderer(canvas, container, props)
+      const { activeCamera } = useCamera()
+
+      const { onLoop } = useRenderLoop()
+
+      const { raycaster, pointer } = useRaycaster()
+
+      onLoop(() => {
+        if (!activeCamera.value) return
+
+        raycaster.value.setFromCamera(pointer.value, activeCamera.value)
+        renderer.value?.render(scene, activeCamera.value)
+      })
+    })
+
+    const app = createTres(slots)
+    app.provide('useTres', useTres())
+    app.provide('extend', extend)
+    app.mount(scene as unknown as TresObject)
+    expose({
+      scene,
+    })
+
+    return () => {
+      return h(
+        h(
+          'div',
+          {
+            ref: container,
+            style: {
+              position: 'relative',
+              width: '100%',
+              height: '100%',
+              pointerEvents: 'auto',
+              touchAction: 'none',
+            },
+          },
+          [
+            h(
+              'div',
+              {
+                style: {
+                  width: '100%',
+                  height: '100%',
+                },
+              },
+              [
+                h('canvas', {
+                  ref: canvas,
+                  style: {
+                    display: 'block',
+                    width: '100%',
+                    height: '100%',
+                    position: props.windowSize ? 'fixed' : 'absolute',
+                    top: 0,
+                    left: 0,
+                  },
+                }),
+              ],
+            ),
+          ],
+        ),
+      )
+    }
+  },
+})
+
+export default TresCanvas

+ 7 - 0
packages/tres/src/composables/index.ts

@@ -1 +1,8 @@
+export * from './useCamera'
+export * from './useRenderLoop/'
+export * from './useRenderer/'
+export * from './useLoader'
+export * from './useTexture'
+export * from './useTres'
+export * from './useRaycaster'
 export * from './useLogger'

+ 10 - 7
packages/tres/src/core/useCamera/index.ts → packages/tres/src/composables/useCamera/index.ts

@@ -1,7 +1,7 @@
-import { useTres } from '/@/core/'
+import { useTres } from '/@/composables/'
 import { PerspectiveCamera, OrthographicCamera } from 'three'
 
-import { toRef, watch, Ref, inject } from 'vue'
+import { toRef, Ref, watchEffect } from 'vue'
 
 export enum CameraType {
   Perspective = 'Perspective',
@@ -104,8 +104,8 @@ let camera: Camera
  * @return {*}  {UseCameraReturn}
  */
 export function useCamera(): UseCameraReturn {
-  const { state, setState } = useTres()
-  const aspectRatio = inject('aspect-ratio')
+  const { state, setState, aspectRatio } = useTres()
+  /* const aspectRatio = inject('aspect-ratio') */
   /**
    * Create camera and push to Tres `state.cameras` array
    *
@@ -182,9 +182,12 @@ export function useCamera(): UseCameraReturn {
   function clearCameras() {
     state.cameras = []
   }
-  if (aspectRatio) {
-    watch(aspectRatio, updateCamera)
-  }
+
+  watchEffect(() => {
+    if (aspectRatio?.value) {
+      updateCamera()
+    }
+  })
 
   return {
     activeCamera: toRef(state, 'camera'),

+ 0 - 0
packages/tres/src/core/useCamera/useCamera.test.ts → packages/tres/src/composables/useCamera/useCamera.test.ts


+ 0 - 0
packages/tres/src/core/useLoader/index.ts → packages/tres/src/composables/useLoader/index.ts


+ 0 - 0
packages/tres/src/core/useLoader/useLoader.test.ts → packages/tres/src/composables/useLoader/useLoader.test.ts


+ 4 - 8
packages/tres/src/core/useRaycaster/index.ts → packages/tres/src/composables/useRaycaster/index.ts

@@ -1,6 +1,6 @@
 import { Raycaster, Vector2 } from 'three'
-import { onUnmounted, provide, Ref, ref, ShallowRef, shallowRef } from 'vue'
-import { useTres } from '/@/core'
+import { Ref, ref, ShallowRef, shallowRef } from 'vue'
+import { useTres } from '/@/composables'
 
 const raycaster = shallowRef(new Raycaster())
 const pointer = ref(new Vector2())
@@ -42,10 +42,6 @@ export function useRaycaster(): UseRaycasterReturn {
   setState('pointer', pointer)
   setState('currentInstance', currentInstance)
 
-  provide('raycaster', raycaster)
-  provide('pointer', pointer)
-  provide('currentInstance', currentInstance)
-
   function onPointerMove(event: MouseEvent) {
     pointer.value.x = (event.clientX / window.innerWidth) * 2 - 1
     pointer.value.y = -(event.clientY / window.innerHeight) * 2 + 1
@@ -53,9 +49,9 @@ export function useRaycaster(): UseRaycasterReturn {
 
   window.addEventListener('pointermove', onPointerMove)
 
-  onUnmounted(() => {
+  /*  onUnmounted(() => {
     window.removeEventListener('pointermove', onPointerMove)
-  })
+  }) */
   return {
     raycaster,
     pointer,

+ 0 - 0
packages/tres/src/core/useRaycaster/useRaycaster.test.ts → packages/tres/src/composables/useRaycaster/useRaycaster.test.ts


+ 0 - 0
packages/tres/src/core/useRenderLoop/index.ts → packages/tres/src/composables/useRenderLoop/index.ts


+ 0 - 0
packages/tres/src/core/useRenderer/const.ts → packages/tres/src/composables/useRenderer/const.ts


+ 1 - 1
packages/tres/src/core/useRenderer/index.ts → packages/tres/src/composables/useRenderer/index.ts

@@ -19,7 +19,7 @@ import {
   Clock,
 } from 'three'
 import type { TextureEncoding, ToneMapping } from 'three'
-import { useRenderLoop, useTres } from '/@/core/'
+import { useRenderLoop, useTres } from '/@/composables/'
 import { normalizeColor } from '/@/utils/normalize'
 import { TresColor } from '/@/types'
 import { rendererPresets, RendererPresetsType } from './const'

+ 0 - 0
packages/tres/src/core/useTexture/index.ts → packages/tres/src/composables/useTexture/index.ts


+ 0 - 0
packages/tres/src/core/useTexture/useTexture.test.ts → packages/tres/src/composables/useTexture/useTexture.test.ts


+ 1 - 1
packages/tres/src/core/useTres/index.ts → packages/tres/src/composables/useTres/index.ts

@@ -1,6 +1,6 @@
 import { Clock, EventDispatcher, Raycaster, Scene, Vector2, WebGLRenderer } from 'three'
 import { computed, ComputedRef, shallowReactive, toRefs } from 'vue'
-import { Camera } from '/@/core'
+import { Camera } from '/@/composables'
 
 export interface TresState {
   /**

+ 0 - 0
packages/tres/src/core/useTres/useTres.test.ts → packages/tres/src/composables/useTres/useTres.test.ts


+ 15 - 0
packages/tres/src/core/catalogue.test.ts

@@ -0,0 +1,15 @@
+import { useTres } from '.'
+import { catalogue, extend } from './catalogue'
+import * as THREE from 'three'
+
+describe('catalog', () => {
+  it('should return a autogenerated uuid', () => {
+    expect(catalogue.value.uuid).toBeDefined()
+  })
+  it('should return a catalog of objects when extended', () => {
+    extend(THREE)
+
+    expect(catalogue.value).toHaveProperty('Mesh')
+    expect(catalogue.value).toHaveProperty('MeshBasicMaterial')
+  })
+})

+ 9 - 0
packages/tres/src/core/catalogue.ts

@@ -0,0 +1,9 @@
+import { MathUtils } from 'three'
+import { Ref, ref } from 'vue'
+import { TresCatalogue } from '../types'
+
+export const catalogue: Ref<TresCatalogue> = ref({ uuid: MathUtils.generateUUID() })
+
+export const extend = (objects: any) => void Object.assign(catalogue.value, objects)
+
+export default { catalogue, extend }

+ 0 - 10
packages/tres/src/core/index.ts

@@ -1,10 +0,0 @@
-export * from './useCamera'
-export * from './useCatalogue'
-export * from './useInstanceCreator'
-export * from './useRenderLoop/'
-export * from './useRenderer/'
-export * from './useScene/'
-export * from './useLoader'
-export * from './useTexture'
-export * from './useTres'
-export * from './useRaycaster'

+ 175 - 0
packages/tres/src/core/nodeOps.ts

@@ -0,0 +1,175 @@
+import { Mesh } from 'three'
+import { useCamera, useRaycaster, useRenderLoop, useLogger } from '/@/composables'
+import { RendererOptions } from 'vue'
+import { catalogue } from './catalogue'
+import { isFunction, useEventListener } from '@vueuse/core'
+import { TresEvent, TresObject } from '../types'
+import { isHTMLTag, kebabToCamel } from '../utils'
+
+const { logWarning } = useLogger()
+
+function hasEvents(obj: any) {
+  for (const prop in obj) {
+    if (prop.indexOf('on') === 0) {
+      return true
+    }
+  }
+  return false
+}
+
+function noop(fn: string): any {
+  fn
+}
+
+let scene: TresObject | null = null
+
+export const nodeOps: RendererOptions<TresObject, TresObject> = {
+  createElement(tag, _isSVG, _anchor, props) {
+    if (tag === 'template') return null
+    if (isHTMLTag(tag)) return null
+    let instance
+
+    if (props === null) props = {}
+
+    if (props?.args) {
+      instance = new catalogue.value[tag.replace('Tres', '')](...props.args)
+    } else {
+      instance = new catalogue.value[tag.replace('Tres', '')]()
+    }
+
+    if (instance.isCamera) {
+      // Let users know that camera is in the center of the scene
+      if (!props?.position || props?.position.every((v: number) => v == 0)) {
+        logWarning(
+          // eslint-disable-next-line max-len
+          'Camera is positioned at the center of the scene [0,0,0], if this is not intentional try setting a position if your scene seems empty 🤗',
+        )
+      }
+      const { pushCamera } = useCamera()
+      pushCamera(instance)
+    }
+
+    if (props?.attach === undefined) {
+      if (instance.isMaterial) instance.attach = 'material'
+      else if (instance.isBufferGeometry) instance.attach = 'geometry'
+    }
+
+    return instance
+  },
+  insert(child, parent, anchor) {
+    if (scene === null && parent.isScene) scene = parent
+    if (parent === null) parent = scene as TresObject
+    //vue core
+    /*  parent.insertBefore(child, anchor || null) */
+    if (parent?.isObject3D && child?.isObject3D) {
+      const index = anchor ? parent.children.indexOf(anchor) : 0
+      child.parent = parent
+      parent.children.splice(index, 0, child)
+      child.dispatchEvent({ type: 'added' })
+    } else if (typeof child?.attach === 'string') {
+      child.__previousAttach = child[parent?.attach]
+      if (parent) {
+        parent[child.attach] = child
+      }
+    }
+
+    const { onLoop } = useRenderLoop()
+
+    // RayCasting
+    let prevInstance: TresEvent | null = null
+    let currentInstance: TresEvent | null = null
+
+    const { raycaster } = useRaycaster()
+    if (child && child instanceof Mesh && hasEvents(child)) {
+      onLoop(() => {
+        if (parent?.children && child && raycaster) {
+          const intersects = raycaster.value.intersectObjects(parent.children)
+
+          if (intersects.length > 0 && intersects[0].object.uuid === child.uuid) {
+            currentInstance = intersects[0]
+
+            if (prevInstance === null || prevInstance.object.uuid !== currentInstance?.object.uuid) {
+              child.onPointerEnter?.(currentInstance)
+            }
+
+            child.onPointerMove?.(currentInstance)
+          } else {
+            currentInstance = null
+            if (prevInstance !== null) {
+              child.onPointerLeave?.(prevInstance)
+            }
+          }
+
+          prevInstance = currentInstance
+        }
+      })
+
+      useEventListener(window, 'click', () => {
+        if (currentInstance === null) return
+        child.onClick?.(currentInstance)
+      })
+    }
+  },
+  remove(node) {
+    if (!node) return
+    const parent = node.parentNode
+    if (parent) {
+      parent.removeChild(node)
+    }
+  },
+  patchProp(node, prop, _prevValue, nextValue) {
+    if (node) {
+      /*       if (node.isCamera && prop === 'look-at') {
+        debugger
+      } */
+      let root = node
+      let key = prop
+      const camelKey = kebabToCamel(key)
+      let target = root?.[camelKey]
+
+      if (!node.parent) {
+        node.parent = scene as TresObject
+      }
+
+      // Traverse pierced props (e.g. foo-bar=value => foo.bar = value)
+      if (key.includes('-') && target === undefined) {
+        const chain = key.split('-')
+        target = chain.reduce((acc, key) => acc[kebabToCamel(key)], root)
+        key = chain.pop() as string
+
+        if (!target?.set) root = chain.reduce((acc, key) => acc[kebabToCamel(key)], root)
+      }
+      let value = nextValue
+      if (value === '') value = true
+      // Set prop, prefer atomic methods if applicable
+      if (isFunction(target)) {
+        /* if (Array.isArray(value)) target(...value)
+        else target(value) */
+        return
+      }
+      if (!target?.set && !isFunction(target)) root[camelKey] = value
+      else if (target.constructor === value.constructor && target?.copy) target?.copy(value)
+      else if (Array.isArray(value)) target.set(...value)
+      else if (!target.isColor && target.setScalar) target.setScalar(value)
+      else target.set(value)
+    }
+  },
+
+  parentNode(node) {
+    return node?.parent || null
+  },
+  createText: () => noop('createText'),
+
+  createComment: () => noop('createComment'),
+
+  setText: () => noop('setText'),
+
+  setElementText: () => noop('setElementText'),
+  nextSibling: () => noop('nextSibling'),
+
+  querySelector: () => noop('querySelector'),
+
+  setScopeId: () => noop('setScopeId'),
+  cloneNode: () => noop('cloneNode'),
+  insertStaticContent: () => noop('insertStaticContent'),
+}

+ 174 - 0
packages/tres/src/core/nodeOpts.test.ts

@@ -0,0 +1,174 @@
+import * as THREE from 'three'
+import { nodeOps } from './nodeOps'
+import { TresObject } from '../types'
+import { extend } from './catalogue'
+import { Mesh, Scene } from 'three'
+
+describe('nodeOps', () => {
+  beforeAll(() => {
+    // Setup
+    extend(THREE)
+  })
+  it('createElement should create an instance with given tag', async () => {
+    // Setup
+    const tag = 'TresMesh'
+    const props = { args: [] }
+
+    // Test
+    const instance = nodeOps.createElement(tag, false, null, props)
+
+    // Assert
+    expect(instance.isObject3D).toBeTruthy()
+    expect(instance).toBeInstanceOf(Mesh)
+  })
+
+  it('createElement should create an instance with given tag and props', async () => {
+    // Setup
+    const tag = 'TresTorusGeometry'
+    const props = { args: [10, 3, 16, 100] }
+
+    // Test
+    const instance = nodeOps.createElement(tag, false, null, props)
+
+    // Assert
+    expect(instance.parameters.radius).toBe(10)
+    expect(instance.parameters.tube).toBe(3)
+    expect(instance.parameters.radialSegments).toBe(16)
+    expect(instance.parameters.tubularSegments).toBe(100)
+  })
+
+  it('createElement should create an camera instance', async () => {
+    // Setup
+    const tag = 'TresPerspectiveCamera'
+    const props = { args: [75, 2, 0.1, 5] }
+
+    // Test
+    const instance = nodeOps.createElement(tag, false, null, props)
+
+    // Assert
+    expect(instance.isCamera).toBeTruthy()
+    expect(instance).toBeInstanceOf(THREE.PerspectiveCamera)
+  })
+
+  it('createElement should log a warning if the camera doesnt have a position', async () => {
+    // Setup
+    const tag = 'TresPerspectiveCamera'
+    const props = { args: [75, 2, 0.1, 5] }
+
+    // Spy
+    const consoleWarnSpy = vi.spyOn(console, 'warn')
+    consoleWarnSpy.mockImplementation(() => {})
+
+    // Test
+    const instance = nodeOps.createElement(tag, false, null, props)
+
+    // Assert
+    expect(instance.isCamera).toBeTruthy()
+    expect(instance).toBeInstanceOf(THREE.PerspectiveCamera)
+    expect(consoleWarnSpy).toHaveBeenCalled()
+  })
+
+  it('createElement should add attach material propety if instance is a material', () => {
+    // Setup
+    const tag = 'TresMeshStandardMaterial'
+    const props = { args: [] }
+
+    // Test
+    const instance = nodeOps.createElement(tag, false, null, props)
+
+    // Assert
+    expect(instance.isMaterial).toBeTruthy()
+    expect(instance.attach).toBe('material')
+  })
+
+  it('createElement should add attach geometry propety if instance is a geometry', () => {
+    // Setup
+    const tag = 'TresTorusGeometry'
+    const props = { args: [] }
+
+    // Test
+    const instance = nodeOps.createElement(tag, false, null, props)
+
+    // Assert
+    expect(instance.isBufferGeometry).toBeTruthy()
+    expect(instance.attach).toBe('geometry')
+  })
+
+  it('insert should insert child into parent', async () => {
+    // Setup
+    const parent: TresObject = new Scene()
+    const child: TresObject = new Mesh()
+
+    // Test
+    nodeOps.insert(child, parent, null)
+
+    // Assert
+    expect(parent.children.includes(child)).toBeTruthy()
+  })
+
+  it('remove: removes child from parent', async () => {
+    // Setup
+    const parent: TresObject = new Scene()
+    const child: TresObject = new Mesh()
+    parent.children.push(child)
+
+    // Test
+    nodeOps.remove(child)
+
+    // Assert
+    expect(!parent.children.includes(child))
+  })
+
+  it('patchProp should patch property of node', async () => {
+    // Setup
+    const node: TresObject = new Mesh()
+    const prop = 'visible'
+    const nextValue = false
+
+    // Test
+    nodeOps.patchProp(node, prop, null, nextValue)
+
+    // Assert
+    expect(node.visible === nextValue)
+  })
+
+  it('patchProp should patch traverse pierced props', async () => {
+    // Setup
+    const node: TresObject = new Mesh()
+    const prop = 'position-x'
+    const nextValue = 5
+
+    // Test
+    nodeOps.patchProp(node, prop, null, nextValue)
+
+    // Assert
+    expect(node.position.x === nextValue)
+  })
+
+  it('patchProp it should not patch traverse pierced props of existing dashed properties', async () => {
+    // Setup
+    const node: TresObject = new Mesh()
+    const prop = 'cast-shadow'
+    const nextValue = true
+
+    // Test
+    nodeOps.patchProp(node, prop, null, nextValue)
+
+    // Assert
+    expect(node.castShadow === nextValue)
+  })
+
+  it('parentNode: returns parent of a node', async () => {
+    // Setup
+    const parent: TresObject = new Scene()
+    const child: TresObject = new Mesh()
+    parent.children.push(child)
+    child.parent = parent
+
+    // Test
+    const parentNode = nodeOps.parentNode(child)
+
+    // Assert
+    expect(parentNode === parent)
+  })
+})

+ 19 - 0
packages/tres/src/core/renderer.ts

@@ -0,0 +1,19 @@
+import * as THREE from 'three'
+
+import { createRenderer, Slots } from 'vue'
+import { extend } from './catalogue'
+import { nodeOps } from './nodeOps'
+
+export const { createApp } = createRenderer(nodeOps)
+
+export const createTres = (slots: Slots) => {
+  const app = createApp(internalFnComponent)
+  function internalFnComponent() {
+    return slots && slots.default ? slots.default() : []
+  }
+  return app
+}
+
+extend(THREE)
+
+export default { createTres, extend }

+ 0 - 69
packages/tres/src/core/useCatalogue/index.ts

@@ -1,69 +0,0 @@
-import { App, ref, Component, Ref } from 'vue'
-import * as THREE from 'three'
-import { useInstanceCreator } from '/@/core'
-import { useLogger } from '/@/composables'
-import { TresCatalogue } from '/@/types'
-
-const catalogue: Ref<TresCatalogue> = ref({ ...THREE, uuid: THREE.MathUtils.generateUUID() })
-
-delete catalogue.value.Scene
-
-let localApp: App
-
-/**
- * State for the catalogue of THREE objects
- *
- * ```ts
- * const { catalogue } = useCatalogue()
- *
- * console.log(catalogue.value.Mesh) // Mesh
- * ```
- *
- * @export
- * @param {App} [app]
- * @param {string} [prefix='Tres']
- * @return {*}
- */
-export function useCatalogue(app?: App, prefix = 'Tres') {
-  const { logError } = useLogger()
-  if (!localApp && app) {
-    localApp = app
-  }
-  const { createComponentInstances } = useInstanceCreator(prefix)
-
-  /**
-   * Extend the catalogue with new THREE objects
-   *
-   * ```ts
-   * const { catalog, extend } = useCatalogue()
-   *
-   * extend({ MyObject: { foo: 'bar' } })
-   *
-   * console.log(catalog.value.MyObject.foo) // bar
-   * ```
-   *
-   * @param {*} objects
-   */
-  const extend = (objects: any) => {
-    if (!objects) {
-      logError('No objects provided to extend catalogue')
-      return
-    }
-    catalogue.value = Object.assign(catalogue.value, objects)
-    const components = createComponentInstances(ref(objects))
-
-    if (localApp) {
-      components.forEach(([key, cmp]) => {
-        // If the component is not already registered, register it
-        if (!localApp._context.components[key as string]) {
-          localApp.component(key as string, cmp as Component)
-        }
-      })
-    }
-  }
-
-  return {
-    extend,
-    catalogue,
-  }
-}

+ 0 - 28
packages/tres/src/core/useCatalogue/useCatalogue.test.ts

@@ -1,28 +0,0 @@
-import { createApp } from 'vue'
-import { withSetup } from '/@/utils/test-utils'
-import { useCatalogue } from './'
-const [composable, app] = withSetup(() => useCatalogue())
-
-describe('useCatalogue', () => {
-  it('should fill the catalogue with THREE objects', () => {
-    const { catalogue } = composable
-
-    expect(catalogue.value).toHaveProperty('Mesh')
-    expect(catalogue.value).toHaveProperty('MeshBasicMaterial')
-  })
-  it('should skip Scene object', () => {
-    const { catalogue } = composable
-
-    expect(catalogue.value).not.toHaveProperty('Scene')
-  })
-  it('should extend the catalogue with objects', () => {
-    const app = createApp({})
-    const { extend, catalogue } = useCatalogue(app)
-
-    extend({ MyObject: { foo: 'bar' } })
-
-    expect(catalogue.value.MyObject.foo).toEqual('bar')
-  })
-
-  // TODO: find a way to mock createComponentInstances to test the component registration
-})

+ 0 - 348
packages/tres/src/core/useInstanceCreator/index.ts

@@ -1,348 +0,0 @@
-/* eslint-disable new-cap */
-/* eslint-disable @typescript-eslint/no-empty-function */
-import { BufferAttribute, Fog, FogBase, Mesh, OrthographicCamera, PerspectiveCamera } from 'three'
-import { defineComponent, inject, onUnmounted, Ref } from 'vue'
-import { useEventListener } from '@vueuse/core'
-
-import { isArray, isDefined, isFunction } from '@alvarosabu/utils'
-import { normalizeVectorFlexibleParam } from '/@/utils/normalize'
-import { useCamera, useCatalogue, useRenderLoop, useTres } from '/@/core/'
-import { useLogger } from '/@/composables'
-import { TresAttributes, TresCatalogue, TresInstance, TresVNode, TresVNodeType, TresEvent } from '/@/types'
-
-const VECTOR3_PROPS = ['rotation', 'scale', 'position']
-const VECTOR3_AXIS = ['X', 'Y', 'Z']
-const COLOR_PROPS = ['color']
-const COLOR_KEYS = ['r', 'g', 'b']
-
-/**
- * Composable responsible for creating instances out of Three.js objects.
- *
- * @export
- * @param {string} prefix
- * @return {*}
- */
-export function useInstanceCreator(prefix: string) {
-  const { /* logMessage, */ logError } = useLogger()
-
-  /**
-   * Process props to `.setAttribute` on instance.
-   *
-   * @example `position` prop will be converted to `setPosition` method call.
-   *
-   * @param {Record<string, any>} props
-   * @param {TresInstance} instance
-   */
-  function processSetAttributes(props: Record<string, any>, instance: TresInstance) {
-    if (!isDefined(props)) return
-    if (!isDefined(instance)) return
-
-    Object.entries(props).forEach(([key, value]) => {
-      const camelKey = key.replace(/(-\w)/g, m => m[1].toUpperCase())
-      instance.setAttribute(camelKey, new BufferAttribute(...(value as ConstructorParameters<typeof BufferAttribute>)))
-    })
-  }
-
-  /**
-   *  Process props to set properties on instance.
-   *
-   * It will also normalize vector3 props and check if the instances property has a `set` method.
-   * If it does, it will call the `set` method with the value, spread if it's an array.
-   *
-   * @example `position=[0,0,0]` prop will be converted to `instance.position.set(0,0,0)` property.
-   *
-   * @param {Record<string, any>} props
-   * @param {TresInstance} instance
-   */
-  function processProps(props: Record<string, any>, instance: TresInstance) {
-    if (!isDefined(props)) return
-    if (!isDefined(instance)) return
-
-    Object.entries(props).forEach(([key, value]) => {
-      const camelKey = key.replace(/(-\w)/g, m => m[1].toUpperCase())
-      let transformProps
-      let transformAxis
-      let colorProps
-      let colorKey
-      // Ignore property args which is use for initial instance construction
-      if (camelKey === 'args' || value === undefined) return
-
-      // Normalize vector3 props
-      if (VECTOR3_PROPS.includes(camelKey) && value) {
-        value = normalizeVectorFlexibleParam(value)
-      } else {
-        VECTOR3_PROPS.forEach(vecProps => {
-          // Check if the props starts with one of the transform props
-          // and is followed only with one of the axis
-          if (camelKey.startsWith(vecProps) && camelKey.length === vecProps.length + 1) {
-            transformProps = vecProps
-            transformAxis = camelKey.substring(vecProps.length)
-            if (!VECTOR3_AXIS.includes(transformAxis)) {
-              logError(
-                // eslint-disable-next-line max-len
-                `There was an error setting ${key} property, ${transformAxis} is not a valid axis for ${transformProps}`,
-              )
-            }
-          }
-        })
-      }
-      COLOR_PROPS.forEach(props => {
-        // Check if the props starts with one of the color props
-        // and is followed only with one of the key
-        if (camelKey.startsWith(props) && camelKey.length === props.length + 1) {
-          colorProps = props
-          colorKey = camelKey.substring(props.length).toLowerCase()
-          if (!COLOR_KEYS.includes(colorKey)) {
-            logError(`There was an error setting ${key} property , ${colorKey} is not a valid axis for ${colorProps}`)
-          }
-        }
-      })
-
-      if (props.ref) {
-        props.ref = instance
-      }
-
-      try {
-        // Check if the property has a "set" method
-        if (instance[camelKey] && isDefined(instance[camelKey].set)) {
-          // Call the "set" method with the value, spread if it's an array
-          instance[camelKey].set(...(isArray(value) ? value : [value]))
-        } else if (
-          // Check if the property has a "setAxis" method
-          transformProps &&
-          instance[transformProps]
-        ) {
-          // Check if setAxis function exist
-          // if it doesn't check if props is rotation
-          if (isDefined(instance[transformProps][`set${transformAxis}`])) {
-            instance[transformProps][`set${transformAxis}`](value)
-          } else if (isDefined(instance[`rotate${transformAxis}`])) {
-            instance[`rotate${transformAxis}`](value)
-          }
-        } else if (
-          // Check if the instance has a "color" property
-          colorProps &&
-          colorKey &&
-          instance[colorProps] &&
-          instance[colorProps][colorKey]
-        ) {
-          instance[colorProps][colorKey] = value
-        } else {
-          // Convert empty strings to `true`
-          if (value === '') {
-            value = true
-          }
-
-          // Check if the property is a function
-          if (isFunction(instance[camelKey])) {
-            if (key === 'center' && !value) return
-            // Call the function with the value, spread if it's an array
-            instance[camelKey](...(isArray(value) ? value : [value]))
-            return
-          }
-
-          // Set the property to the value
-          instance[camelKey] = value
-        }
-      } catch (error: unknown) {
-        logError(`There was an error setting ${camelKey} property`, error as Error)
-      }
-    })
-  }
-
-  /**
-   * Proccess slots to add children to instance.
-   *
-   * @param {TresVNode} vnode
-   * @return {*}  {(TresInstance | TresInstance[] | undefined)}
-   */
-  function createInstanceFromVNode(vnode: TresVNode): TresInstance | TresInstance[] | undefined {
-    const fragmentRegex = /^Symbol\(Fragment\)$/g
-    const textRegex = /^Symbol\(Text\)$/g
-    const commentRegex = /^Symbol\(Comment\)$/g
-    // Check if the vnode is a Fragment
-    if (fragmentRegex.test(vnode.type.toString())) {
-      return vnode.children.map(child => createInstanceFromVNode(child as TresVNode)) as TresInstance[]
-    } else if (textRegex.test(vnode.type.toString()) || commentRegex.test(vnode.type.toString())) {
-      return
-    } else {
-      const vNodeType = ((vnode.type as TresVNodeType).name as string).replace(prefix, '')
-
-      const catalogue = inject<Ref<TresCatalogue>>('catalogue')
-
-      // check if args prop is defined on the vnode
-      let internalInstance
-      if (catalogue) {
-        if ((vnode.children as unknown as { default: any })?.default) {
-          const internal = (vnode.children as unknown as { default: any })
-            .default()
-            .map((child: TresVNode) => createInstanceFromVNode(child)) as TresInstance[]
-
-          internalInstance = new catalogue.value[vNodeType](...internal.flat().filter(Boolean))
-        } else if (vnode?.props?.args) {
-          // if args prop is defined, create new instance of catalogue[vNodeType] with the provided arguments
-          if (catalogue?.value[vNodeType]) {
-            internalInstance = new catalogue.value[vNodeType](...vnode.props.args)
-          } else {
-            logError(`There is no ${vNodeType} in the catalogue`, catalogue?.value.uuid)
-          }
-        } else {
-          // if args prop is not defined, create a new instance of catalogue[vNodeType] without arguments
-          internalInstance = new catalogue.value[vNodeType]()
-        }
-      }
-
-      // check if props is defined on the vnode
-      if (vnode?.props) {
-        // if props is defined, process the props and pass the internalInstance to update its properties
-        if (vNodeType === 'BufferGeometry') {
-          processSetAttributes(vnode.props, internalInstance)
-        } else {
-          processProps(vnode.props, internalInstance)
-        }
-      }
-      return internalInstance
-    }
-  }
-
-  /**
-   * Create a new instance of a ThreeJS object based on the component attrs and slots.
-   *
-   * Checks if the component has slots,
-   * if it does, it will create a new Object3D instance passing the slots instances as properties
-   * Example:
-   *
-   * ```vue
-   * <TresMesh>
-   *  <TresBoxGeometry />
-   *  <TresMeshBasicMaterial />
-   * </TresMesh>
-   * ```
-   *
-   * will create a new Mesh instance with a BoxGeometry and a MeshBasicMaterial
-   * const mesh = new Mesh(new BoxGeometry(), new MeshBasicMaterial())
-   *
-   * @param {*} threeObj
-   * @param {TresAttributes} attrs
-   * @param {Record<string, any>} slots
-   * @return {*}  {TresInstance}
-   */
-  function createInstance(threeObj: any, attrs: TresAttributes, slots: Record<string, any>): TresInstance {
-    if (slots.default && slots?.default()) {
-      const internal = slots.default().map((vnode: TresVNode) => createInstanceFromVNode(vnode))
-      if (threeObj.name === 'Group') {
-        const group = new threeObj()
-        internal.forEach((child: TresInstance) => {
-          group.add(child)
-        })
-        return group
-      } else {
-        return new threeObj(...internal.flat().filter(Boolean))
-      }
-    } else {
-      // Creates a new THREE instance, if args is present, spread it on the constructor
-      return attrs.args ? new threeObj(...attrs.args) : new threeObj()
-    }
-  }
-
-  /**
-   * Creates a new component instance for each object in the catalogue
-   *
-   * @param {Ref<TresCatalogue>} catalogue
-   * @return {*}
-   */
-  function createComponentInstances(catalogue: Ref<TresCatalogue>) {
-    return (
-      Object.entries(catalogue.value)
-        // eslint-disable-next-line @typescript-eslint/no-unused-vars
-        .filter(([_key, value]) => (value as { prototype: any })?.prototype?.constructor?.toString().includes('class'))
-        .map(([key, threeObj]) => {
-          const name = `${prefix}${key}`
-          const cmp = defineComponent({
-            name,
-            setup(_props, { slots, attrs, ...ctx }) {
-              const { state } = useTres()
-              const { onLoop } = useRenderLoop()
-              const scene = state.scene
-              const raycaster = state.raycaster
-
-              let instance = createInstance(threeObj, attrs, slots)
-              processProps(attrs, instance)
-              // If the instance is a camera, push it to the camera stack
-              if (instance instanceof PerspectiveCamera || instance instanceof OrthographicCamera) {
-                const { pushCamera } = useCamera()
-                pushCamera(instance)
-              }
-
-              // If the instance is a valid Object3D, add it to the scene
-              if (instance.isObject3D) {
-                scene?.add(instance)
-              }
-
-              let prevInstance: TresEvent | null = null
-              let currentInstance: TresEvent | null = null
-              if (instance instanceof Mesh) {
-                onLoop(() => {
-                  if (instance && raycaster && scene?.children) {
-                    const intersects = raycaster.intersectObjects(scene?.children)
-
-                    if (intersects.length > 0) {
-                      currentInstance = intersects[0]
-
-                      if (prevInstance === null || prevInstance.object.uuid !== currentInstance?.object.uuid) {
-                        ctx.emit('pointer-enter', currentInstance)
-                      }
-
-                      ctx.emit('pointer-move', currentInstance)
-                    } else {
-                      currentInstance = null
-                      if (prevInstance !== null) {
-                        ctx.emit('pointer-leave', prevInstance)
-                      }
-                    }
-
-                    prevInstance = currentInstance
-                  }
-                })
-
-                const clickEventListener = useEventListener(window, 'click', () => {
-                  ctx.emit('click', prevInstance)
-                })
-
-                onUnmounted(() => {
-                  clickEventListener()
-                })
-              }
-
-              if (scene && instance instanceof Fog) {
-                scene.fog = instance as unknown as FogBase
-              }
-
-              if (import.meta.hot) {
-                import.meta.hot.on('vite:afterUpdate', () => {
-                  instance = createInstance(threeObj, attrs, slots)
-                  processProps(attrs, instance)
-
-                  if (instance.isObject3D) {
-                    scene?.add(instance)
-                  }
-                })
-              }
-
-              ctx.expose(instance)
-
-              return () => {}
-            },
-          })
-
-          return [name, cmp]
-        })
-    )
-  }
-
-  return {
-    createComponentInstances,
-    processProps,
-    createInstanceFromVNode,
-  }
-}

+ 0 - 27
packages/tres/src/core/useInstanceCreator/useInstanceCreator.test.ts

@@ -1,27 +0,0 @@
-import { describe } from 'vitest'
-import { shallowRef } from 'vue'
-import { useInstanceCreator } from '.'
-import { useTres } from '../useTres'
-import { withSetup } from '/@/utils/test-utils'
-
-const [composable, app] = withSetup(() => useInstanceCreator('Tres'))
-
-describe('useInstanceCreator', () => {
-  // TODO: understand why this is not working
-  it.todo('should create component instances', () => {
-    const { createComponentInstances } = composable
-    const catalogue = shallowRef({
-      TresBox: { name: 'TresBox' },
-      TresSphere: { name: 'TresSphere' },
-      TresPlane: { name: 'TresPlane' },
-    })
-    app.provide('catalogue', catalogue)
-
-    app.provide('useTres', useTres())
-    const components = createComponentInstances(catalogue)
-    expect(components).toHaveLength(3)
-    expect(components[0][0]).toBe('TresBox')
-    expect(components[1][0]).toBe('TresSphere')
-    expect(components[2][0]).toBe('TresPlane')
-  })
-})

+ 0 - 103
packages/tres/src/core/useRenderer/component.ts

@@ -1,103 +0,0 @@
-import { RendererPresetsType } from './const'
-import { ShadowMapType, TextureEncoding, ToneMapping } from 'three'
-import { h, defineComponent, ref, provide, onBeforeUnmount, PropType } from 'vue'
-import { useRenderer } from '.'
-import { useLogger } from '/@/composables'
-import { TresVNodeType } from '/@/types'
-
-/**
- * Vue component for rendering a Tres component.
- */
-
-const { logError, logWarning } = useLogger()
-
-export const TresCanvas = defineComponent({
-  name: 'TresCanvas',
-  props: {
-    shadows: Boolean,
-    shadowMapType: Number as PropType<ShadowMapType>,
-    physicallyCorrectLights: {
-      type: Boolean,
-      default: false,
-      validator: (value: boolean) => {
-        if (value) {
-          logWarning('physicallyCorrectLights is deprecated. Use useLegacyLights instead.')
-        }
-        return true
-      },
-    },
-    useLegacyLights: Boolean,
-    outputEncoding: Number as PropType<TextureEncoding>,
-    toneMapping: Number as PropType<ToneMapping>,
-    toneMappingExposure: Number,
-    context: Object as PropType<WebGLRenderingContext>,
-    powerPreference: String as PropType<'high-performance' | 'low-power' | 'default'>,
-    preserveDrawingBuffer: Boolean,
-    clearColor: String,
-    windowSize: { type: Boolean, default: false },
-    preset: String as PropType<RendererPresetsType>,
-  },
-  setup(props, { slots, attrs }) {
-    const canvas = ref<HTMLCanvasElement>()
-    const container = ref<HTMLElement>()
-
-    const { renderer, dispose, aspectRatio } = useRenderer(canvas, container, props)
-
-    provide('aspect-ratio', aspectRatio)
-    provide('renderer', renderer)
-
-    if (slots.default && !slots.default().some(node => (node.type as TresVNodeType).name === 'Scene')) {
-      logError('TresCanvas must contain a Scene component.')
-    }
-    if (slots.default && !slots.default().some(node => (node.type as TresVNodeType).name?.includes('Camera'))) {
-      logError('Scene must contain a Camera component.')
-    }
-
-    onBeforeUnmount(() => dispose())
-
-    return () => {
-      if (slots.default) {
-        return h(
-          'div',
-          {
-            ref: container,
-            style: {
-              position: 'relative',
-              width: '100%',
-              height: '100%',
-              overflow: 'hidden',
-              pointerEvents: 'auto',
-              touchAction: 'none',
-              ...(attrs.style as Record<string, unknown>),
-            },
-          },
-          [
-            h(
-              'div',
-              {
-                style: {
-                  width: '100%',
-                  height: '100%',
-                },
-              },
-              [
-                h('canvas', {
-                  ref: canvas,
-                  style: {
-                    display: 'block',
-                    width: '100%',
-                    height: '100%',
-                    position: props.windowSize ? 'fixed' : 'absolute',
-                    top: 0,
-                    left: 0,
-                  },
-                }),
-                slots.default(),
-              ],
-            ),
-          ],
-        )
-      }
-    }
-  },
-})

+ 0 - 42
packages/tres/src/core/useScene/component.ts

@@ -1,42 +0,0 @@
-import { defineComponent, inject, provide, Ref } from 'vue'
-import type { Renderer } from 'three'
-import { useCamera, useTres, useRenderLoop, useScene, useRaycaster } from '/@/core/'
-
-/**
- * Vue component for rendering a Tres component.
- */
-export const Scene = defineComponent({
-  name: 'Scene',
-  setup(_props, { slots }) {
-    const { setState } = useTres()
-    const { scene } = useScene()
-    const renderer = inject<Ref<Renderer>>('renderer')
-    const { activeCamera } = useCamera()
-    const { raycaster, pointer } = useRaycaster()
-    const { onLoop } = useRenderLoop()
-
-    provide('local-scene', scene)
-    setState('scene', scene.value)
-
-    onLoop(() => {
-      if (!activeCamera.value) return
-      raycaster.value.setFromCamera(pointer.value, activeCamera.value)
-
-      if (renderer?.value && activeCamera && scene?.value) {
-        renderer.value.render(scene?.value, activeCamera.value)
-      }
-    })
-
-    if (import.meta.hot) {
-      import.meta.hot.on('vite:afterUpdate', () => {
-        scene.value.children = []
-      })
-    }
-
-    return () => {
-      if (slots.default) {
-        return slots.default()
-      }
-    }
-  },
-})

+ 0 - 16
packages/tres/src/core/useScene/index.ts

@@ -1,16 +0,0 @@
-import { Scene } from 'three'
-import { shallowRef } from 'vue'
-
-const scene = shallowRef(new Scene())
-
-/**
- * Composable for accessing the scene.
- *
- * @export
- * @return {*} {ShallowRef<Scene>}
- */
-export function useScene() {
-  return {
-    scene,
-  }
-}

+ 0 - 10
packages/tres/src/core/useScene/useScene.test.ts

@@ -1,10 +0,0 @@
-import { Scene } from 'three'
-import { describe, test, expect } from 'vitest'
-import { useScene } from './'
-
-describe('useScene()', () => {
-  test('should init a scene', () => {
-    const { scene } = useScene()
-    expect(scene.value).toBeInstanceOf(Scene)
-  })
-})

+ 28 - 0
packages/tres/src/demos/AkuAku.vue

@@ -0,0 +1,28 @@
+<script setup lang="ts">
+import { useTweakPane, useGLTF } from '@tresjs/cientos'
+import { inject, ref, watch, watchEffect } from 'vue'
+
+useTweakPane()
+
+const { scene: model } = await useGLTF(
+  'https://raw.githubusercontent.com/Tresjs/assets/main/models/gltf/aku-aku/AkuAku.gltf',
+  {
+    draco: true,
+  },
+)
+model.position.set(0, 4, 0)
+model.updateMatrixWorld()
+
+const akuAkuRef = ref(null)
+
+watch(akuAkuRef, value => {
+  console.log('akuAkuRef', value)
+})
+
+const awiwi = inject('awiwi')
+console.log('awiwi', awiwi)
+</script>
+
+<template>
+  <TresMesh ref="akuAkuRef" v-bind="model" />
+</template>

+ 0 - 0
packages/tres/src/components/AnimatedModel.vue → packages/tres/src/demos/AnimatedModel.vue


+ 18 - 19
packages/tres/src/components/FBXModels.vue → packages/tres/src/demos/FBXModels.vue

@@ -1,7 +1,7 @@
 <script setup lang="ts">
 import { ref, watch } from 'vue'
 import { Color, sRGBEncoding } from 'three'
-
+import { TresCanvas } from '../components/TresCanvas'
 import { OrbitControls, useTweakPane, FBXModel, useFBX } from '../../../cientos/src/'
 
 const bgColor = new Color('#F78B3D')
@@ -22,22 +22,21 @@ watch(jeepRef, ({ getModel }) => {
 </script>
 
 <template>
-  <Suspense>
-    <TresCanvas
-      :clear-color="bgColor"
-      shadows
-      alpha
-      window-size
-      power-preference="high-performance"
-      :output-encoding="sRGBEncoding"
-    >
-      <OrbitControls />
-      <TresPerspectiveCamera :position="8" :fov="45" :near="0.1" :far="10000" />
-      <TresScene :fog="bgColor">
-        <TresAmbientLight :color="0xffffff" :intensity="0.75" />
-        <TresMesh v-bind="model" />
-        <FBXModel ref="jeepRef" path="/models/low-poly-truck/Jeep_done.fbx" />
-      </TresScene>
-    </TresCanvas>
-  </Suspense>
+  <TresCanvas
+    :clear-color="bgColor"
+    shadows
+    alpha
+    window-size
+    power-preference="high-performance"
+    :output-encoding="sRGBEncoding"
+  >
+    <OrbitControls />
+    <TresPerspectiveCamera :position="8" :fov="45" :near="0.1" :far="10000" />
+
+    <TresAmbientLight :color="0xffffff" :intensity="0.75" />
+    <TresMesh v-bind="model" />
+    <Suspense>
+      <FBXModel ref="jeepRef" path="/models/low-poly-truck/Jeep_done.fbx" />
+    </Suspense>
+  </TresCanvas>
 </template>

+ 0 - 0
packages/tres/src/components/Responsiveness.vue → packages/tres/src/demos/Responsiveness.vue


+ 133 - 0
packages/tres/src/demos/Shapes.vue

@@ -0,0 +1,133 @@
+<script setup lang="ts">
+import { BasicShadowMap, CubicBezierCurve3, DoubleSide, NoToneMapping, sRGBEncoding, Vector3 } from 'three'
+import { reactive, shallowRef, watch } from 'vue'
+import { TresCanvas } from '/@/components/TresCanvas'
+import {
+  Plane,
+  Tube,
+  Box,
+  Sphere,
+  Torus,
+  Ring,
+  TorusKnot,
+  Tetrahedron,
+  Icosahedron,
+  Octahedron,
+  Dodecahedron,
+  Circle,
+  Cone,
+  OrbitControls,
+} from '../../../cientos/src/'
+
+const state = reactive({
+  clearColor: '#82DBC5',
+  shadows: true,
+  alpha: false,
+  physicallyCorrectLights: true,
+  shadowMapType: BasicShadowMap,
+  outputEncoding: sRGBEncoding,
+  toneMapping: NoToneMapping,
+})
+
+const planeRef = shallowRef()
+const boxRef = shallowRef()
+const torusRef = shallowRef()
+const torusKnotRef = shallowRef()
+const circleRef = shallowRef()
+const tubeRef = shallowRef()
+const ringRef = shallowRef()
+const tetrahedronRef = shallowRef()
+const icosahedronRef = shallowRef()
+const octahedronRef = shallowRef()
+const dodecahedronRef = shallowRef()
+
+watch(planeRef, plane => {
+  console.log('plane', plane.value.position)
+})
+watch(boxRef, box => {
+  console.log('box', box.value.position)
+})
+watch(torusRef, torus => {
+  console.log('torus', torus.value.position)
+})
+watch(torusKnotRef, torusKnot => {
+  console.log('torusKnot', torusKnot.value.position)
+})
+watch(circleRef, circle => {
+  console.log('circle', circle.value.position)
+})
+watch(tubeRef, tube => {
+  console.log('tube', tube.value.position)
+})
+watch(ringRef, ring => {
+  console.log('ring', ring.value.position)
+})
+watch(tetrahedronRef, tetrahedron => {
+  console.log('tetrahedron', tetrahedron.value.position)
+})
+watch(icosahedronRef, icosahedron => {
+  console.log('icosahedron', icosahedron.value.position)
+})
+watch(octahedronRef, octahedron => {
+  console.log('octahedron', octahedron.value.position)
+})
+watch(dodecahedronRef, dodecahedron => {
+  console.log('dodecahedron', dodecahedron.value.position)
+})
+
+const tubePath = new CubicBezierCurve3(
+  new Vector3(-1, 0, 0),
+  new Vector3(-0.5, -1, 0),
+  new Vector3(0.5, 1, 0),
+  new Vector3(1, 0, 0),
+)
+</script>
+
+<template>
+  <TresCanvas v-bind="state">
+    <TresPerspectiveCamera :position="[5, 5, 5]" :fov="75" :aspect="1" :near="0.1" :far="1000" />
+    <OrbitControls />
+
+    <TresAmbientLight :color="0xffffff" :intensity="1" />
+    <TresDirectionalLight :position="[0, 8, 4]" :intensity="0.7" cast-shadow />
+    <Plane ref="planeRef" :args="[12, 8]" :position="[-2, 4, 0]" receive-shadow>
+      <TresMeshToonMaterial color="teal" />
+    </Plane>
+    <Box ref="boxRef" :arg0s="[1, 1, 1]" :position="[0, 6, 0]" cast-shadow>
+      <TresMeshToonMaterial color="orange" />
+    </Box>
+    <Sphere ref="sphereRef" :args="[1, 32, 16]" :position="[2, 6, 0]" cast-shadow>
+      <TresMeshToonMaterial color="pink" />
+    </Sphere>
+    <Torus ref="torusRef" :args="[0.75, 0.4, 16, 80]" :position="[-2, 6, 0]" cast-shadow>
+      <TresMeshToonMaterial color="cyan" />
+    </Torus>
+    <TorusKnot ref="torusKnotRef" :args="[0.6, 0.2, 64, 8]" :position="[-2, 6, 2]" cast-shadow>
+      <TresMeshToonMaterial color="lime" />
+    </TorusKnot>
+    <Circle ref="circleRef" :args="[0.9, 32]" :position="[0, 6, 2]" :rotation="[Math.PI, 0, 0]" cast-shadow>
+      <TresMeshToonMaterial color="lightsalmon" :side="DoubleSide" />
+    </Circle>
+    <Cone ref="coneRef" :args="[1, 1, 6]" :position="[2, 6, 2]" :rotation="[Math.PI, 0, 0]" cast-shadow>
+      <TresMeshToonMaterial color="slateblue" />
+    </Cone>
+    <Tube ref="tubeRef" :args="[tubePath, 20, 0.2, 8, false]" :position="[2, 6, -2]" cast-shadow>
+      <TresMeshToonMaterial color="lightblue" />
+    </Tube>
+    <Ring ref="ringRef" :args="[0.5, 1, 32]" :position="[0, 6, -2]" :rotation="[Math.PI, 0, 0]" cast-shadow>
+      <TresMeshToonMaterial color="purple" :side="DoubleSide" />
+    </Ring>
+    <Tetrahedron ref="tetrahedronRef" :args="[1, 0]" :position="[-2, 6, -2]" cast-shadow>
+      <TresMeshToonMaterial color="yellow" />
+    </Tetrahedron>
+    <Icosahedron ref="icosahedronRef" :args="[1, 0]" :position="[-4, 6, -2]" cast-shadow>
+      <TresMeshToonMaterial color="red" />
+    </Icosahedron>
+    <Octahedron ref="octahedronRef" :args="[1, 0]" :position="[-4, 6, 0]" cast-shadow>
+      <TresMeshToonMaterial color="greenyellow" />
+    </Octahedron>
+    <Dodecahedron ref="dodecahedronRef" :args="[1, 0]" :position="[-4, 6, 2]" cast-shadow>
+      <TresMeshToonMaterial color="deeppink" />
+    </Dodecahedron>
+  </TresCanvas>
+</template>

+ 32 - 0
packages/tres/src/demos/TestSphere.vue

@@ -0,0 +1,32 @@
+<!-- eslint-disable max-len -->
+<script setup lang="ts">
+import { Ref, ref } from 'vue'
+import { useRenderLoop, useTexture } from '/@/composables/'
+import { TresInstance } from '../types'
+
+const sphereRef: Ref<TresInstance | null> = ref(null)
+
+const { onLoop, resume } = useRenderLoop()
+resume()
+onLoop(({ elapsed }) => {
+  if (sphereRef.value) {
+    sphereRef.value.position.y = Math.sin(elapsed * 0.2) * 2.0
+  }
+})
+
+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',
+})
+</script>
+<template>
+  <TresMesh ref="sphereRef" :position="[-2, 2, 2]" :scale="1" cast-shadow>
+    <TresSphereGeometry :args="[1, 500, 500]" />
+    <TresMeshStandardMaterial v-bind="pbrTexture" />
+  </TresMesh>
+</template>

+ 3 - 3
packages/tres/src/components/Text3D.vue → packages/tres/src/demos/Text3D.vue

@@ -1,10 +1,10 @@
 <script setup lang="ts">
 import { TextGeometry } from 'three/examples/jsm/geometries/TextGeometry'
 import { FontLoader } from 'three/examples/jsm/loaders/FontLoader'
-import { useCatalogue, useTexture } from '/@/core'
-const { extend } = useCatalogue()
+import { extend } from '../core/catalogue'
+import { useTexture } from '/@/composables'
 
-extend({ TextGeometry: TextGeometry })
+extend({ TextGeometry })
 
 const fontPath = 'https://raw.githubusercontent.com/Tresjs/assets/main/fonts/FiraCodeRegular.json'
 

+ 0 - 0
packages/tres/src/components/TheBasic.vue → packages/tres/src/demos/TheBasic.vue


+ 0 - 0
packages/tres/src/components/TheEnvironment.vue → packages/tres/src/demos/TheEnvironment.vue


+ 0 - 0
packages/tres/src/components/TheEvents.vue → packages/tres/src/demos/TheEvents.vue


+ 0 - 0
packages/tres/src/components/TheExperience.vue → packages/tres/src/demos/TheExperience.vue


+ 11 - 14
packages/tres/src/components/TheGizmos.vue → packages/tres/src/demos/TheGizmos.vue

@@ -1,7 +1,7 @@
 <script setup lang="ts">
 import { shallowRef, shallowReactive } from 'vue'
 import { BasicShadowMap, sRGBEncoding, NoToneMapping } from 'three'
-
+import { TresCanvas } from '../components/TresCanvas'
 import { OrbitControls, useTweakPane, TransformControls } from '../../../cientos/src'
 
 const state = shallowReactive({
@@ -75,18 +75,15 @@ axisFolder.addInput(transformState, 'showZ')
     <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>
+    <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 />
   </TresCanvas>
 </template>

+ 1 - 1
packages/tres/src/components/TheGroups.vue → packages/tres/src/demos/TheGroups.vue

@@ -1,5 +1,5 @@
 <script setup lang="ts">
-import { useRenderLoop } from '/@/core/useRenderLoop'
+import { useRenderLoop } from '/@/composables/useRenderLoop'
 import { ref } from 'vue'
 import { OrbitControls } from '../../../cientos/src/'
 

+ 0 - 0
packages/tres/src/components/TheParticles.vue → packages/tres/src/demos/TheParticles.vue


+ 0 - 0
packages/tres/src/components/TheSmallExperience.vue → packages/tres/src/demos/TheSmallExperience.vue


+ 0 - 0
packages/tres/src/components/VectorSetProps.vue → packages/tres/src/demos/VectorSetProps.vue


+ 6 - 25
packages/tres/src/index.ts

@@ -1,13 +1,11 @@
-import { App, Component } from 'vue'
-import { TresCanvas } from '/@/core/useRenderer/component'
-import { Scene } from '/@/core/useScene/component'
-import { useCatalogue, useInstanceCreator, useTres } from '/@/core'
-export * from '/@/core'
+import { App } from 'vue'
+import { TresCanvas } from '/@/components/TresCanvas'
+export * from '/@/composables'
+export * from '/@/core/catalogue'
 export * from './keys'
 export * from './types'
 
 export interface TresOptions {
-  prefix?: string
   extends?: Record<string, unknown>
 }
 export interface TresPlugin {
@@ -16,26 +14,9 @@ export interface TresPlugin {
 }
 
 const plugin: TresPlugin = {
-  install(app: App, options) {
-    const prefix = options?.prefix || 'Tres'
-
+  install(app: App) {
     // Register core components
-    app.component(`${prefix}Canvas`, TresCanvas)
-    app.component(`${prefix}Scene`, Scene)
-
-    // Initialize catalogue
-    const { catalogue, extend } = useCatalogue(app, prefix)
-    app.provide('catalogue', catalogue)
-    app.provide('extend', extend)
-    app.provide('useTres', useTres())
-
-    // Create components from catalogue
-    const { createComponentInstances } = useInstanceCreator(prefix)
-    const components = createComponentInstances(catalogue)
-
-    components.forEach(([key, cmp]) => {
-      app.component(key as string, cmp as Component)
-    })
+    app.component(`TresCanvas`, TresCanvas)
   },
 }
 

+ 3 - 2
packages/tres/src/main.ts

@@ -1,9 +1,10 @@
 import { createApp } from 'vue'
 import App from './App.vue'
-import plugin from '.'
+
 import './style.css'
 
 export const app = createApp(App)
 
-app.use(plugin)
 app.mount('#app')
+
+console.log(app)

+ 4 - 0
packages/tres/src/types/index.ts

@@ -10,6 +10,10 @@ export type TresObject = Object3D<Event> & {
   color?: TresColor
   opacity?: number
   visible?: boolean
+  attach?: string
+  parent: TresObject | null
+  dispose?: () => void
+  __previousAttach?: string
   [key: string]: any
 }
 

+ 26 - 0
packages/tres/src/utils/index.ts

@@ -12,3 +12,29 @@ export const merge = (target: any, source: any) => {
   Object.assign(target || {}, source)
   return target
 }
+
+const HTML_TAGS =
+  'html,body,base,head,link,meta,style,title,address,article,aside,footer,' +
+  'header,hgroup,h1,h2,h3,h4,h5,h6,nav,section,div,dd,dl,dt,figcaption,' +
+  'figure,picture,hr,img,li,main,ol,p,pre,ul,a,b,abbr,bdi,bdo,br,cite,code,' +
+  'data,dfn,em,i,kbd,mark,q,rp,rt,ruby,s,samp,small,span,strong,sub,sup,' +
+  'time,u,var,wbr,area,audio,map,track,video,embed,object,param,source,' +
+  'canvas,script,noscript,del,ins,caption,col,colgroup,table,thead,tbody,td,' +
+  'th,tr,button,datalist,fieldset,form,input,label,legend,meter,optgroup,' +
+  'option,output,progress,select,textarea,details,dialog,menu,' +
+  'summary,template,blockquote,iframe,tfoot'
+
+export const isHTMLTag = /*#__PURE__*/ makeMap(HTML_TAGS)
+
+export function kebabToCamel(str: string) {
+  return str.replace(/-([a-z])/g, (_, c) => c.toUpperCase())
+}
+
+export function makeMap(str: string, expectsLowerCase?: boolean): (key: string) => boolean {
+  const map: Record<string, boolean> = Object.create(null)
+  const list: Array<string> = str.split(',')
+  for (let i = 0; i < list.length; i++) {
+    map[list[i]] = true
+  }
+  return expectsLowerCase ? val => !!map[val.toLowerCase()] : val => !!map[val]
+}

+ 5 - 0
packages/tres/vite.config.ts

@@ -31,6 +31,11 @@ export default defineConfig({
   plugins: [
     vue({
       isProduction: false,
+      template: {
+        compilerOptions: {
+          isCustomElement: tag => tag.startsWith('Tres') && tag !== 'TresCanvas',
+        },
+      },
     }),
     dts({
       insertTypesEntry: true,

+ 74 - 70
pnpm-lock.yaml

@@ -9,7 +9,7 @@ importers:
       '@changesets/cli': ^2.25.2
       '@stackblitz/sdk': ^1.8.1
       '@tresjs/cientos': workspace:^1.8.0
-      '@tresjs/core': workspace:^1.8.1
+      '@tresjs/core': workspace:^2.0.0
       '@typescript-eslint/eslint-plugin': ^5.42.0
       '@typescript-eslint/parser': ^5.42.0
       conventional-changelog-cli: ^2.2.2
@@ -47,7 +47,7 @@ importers:
 
   packages/cientos:
     specifiers:
-      '@tresjs/core': workspace:^1.8.1
+      '@tresjs/core': workspace:^2.0.0
       '@tweakpane/plugin-essentials': ^0.1.8
       '@vitejs/plugin-vue': ^4.0.0
       kolorist: ^1.7.0
@@ -82,9 +82,9 @@ importers:
       '@tresjs/cientos': workspace:^1.8.0
       '@types/three': latest
       '@vitejs/plugin-vue': ^4.0.0
-      '@vitest/coverage-c8': ^0.28.5
-      '@vitest/ui': ^0.28.5
-      '@vue/test-utils': ^2.3.0
+      '@vitest/coverage-c8': ^0.29.2
+      '@vitest/ui': ^0.29.2
+      '@vue/test-utils': ^2.3.1
       '@vueuse/core': ^9.13.0
       happy-dom: ^8.7.1
       jsdom: ^21.1.0
@@ -95,11 +95,11 @@ importers:
       three: latest
       vite: ^4.1.4
       vite-plugin-banner: ^0.7.0
-      vite-plugin-dts: 2.0.0-beta.1
+      vite-plugin-dts: 2.1.0
       vite-plugin-glsl: ^1.1.2
-      vite-plugin-inspect: ^0.7.15
+      vite-plugin-inspect: ^0.7.16
       vite-plugin-require-transform: ^1.0.9
-      vitest: ^0.28.5
+      vitest: ^0.29.2
       vue-demi: ^0.13.11
     dependencies:
       '@alvarosabu/utils': 2.3.0
@@ -108,9 +108,9 @@ importers:
       '@tresjs/cientos': link:../cientos
       '@types/three': 0.149.0
       '@vitejs/plugin-vue': 4.0.0_vite@4.1.4
-      '@vitest/coverage-c8': 0.28.5_7o7wrzczp3bjambnh5yw6wrpda
-      '@vitest/ui': 0.28.5
-      '@vue/test-utils': 2.3.0
+      '@vitest/coverage-c8': 0.29.2_vitest@0.29.2
+      '@vitest/ui': 0.29.2
+      '@vue/test-utils': 2.3.1
       happy-dom: 8.7.1
       jsdom: 21.1.0
       kolorist: 1.7.0
@@ -120,11 +120,11 @@ importers:
       three: 0.150.1
       vite: 4.1.4
       vite-plugin-banner: 0.7.0
-      vite-plugin-dts: 2.0.0-beta.1_vite@4.1.4
+      vite-plugin-dts: 2.1.0_vite@4.1.4
       vite-plugin-glsl: 1.1.2_vite@4.1.4
-      vite-plugin-inspect: 0.7.15_vite@4.1.4
+      vite-plugin-inspect: 0.7.16_vite@4.1.4
       vite-plugin-require-transform: 1.0.9
-      vitest: 0.28.5_7o7wrzczp3bjambnh5yw6wrpda
+      vitest: 0.29.2_ck7bzyzbhiuhyu6l53oypc6j6a
       vue-demi: 0.13.11
 
 packages:
@@ -1501,51 +1501,41 @@ packages:
       vue: 3.2.47
     dev: true
 
-  /@vitest/coverage-c8/0.28.5_7o7wrzczp3bjambnh5yw6wrpda:
-    resolution: {integrity: sha512-zCNyurjudoG0BAqAgknvlBhkV2V9ZwyYLWOAGtHSDhL/St49MJT+V2p1G0yPaoqBbKOTATVnP5H2p1XL15H75g==}
+  /@vitest/coverage-c8/0.29.2_vitest@0.29.2:
+    resolution: {integrity: sha512-NmD3WirQCeQjjKfHu4iEq18DVOBFbLn9TKVdMpyi5YW2EtnS+K22/WE+9/wRrepOhyeTxuEFgxUVkCAE1GhbnQ==}
+    peerDependencies:
+      vitest: '>=0.29.0 <1'
     dependencies:
       c8: 7.13.0
       picocolors: 1.0.0
       std-env: 3.3.2
-      vitest: 0.28.5_7o7wrzczp3bjambnh5yw6wrpda
-    transitivePeerDependencies:
-      - '@edge-runtime/vm'
-      - '@vitest/browser'
-      - '@vitest/ui'
-      - happy-dom
-      - jsdom
-      - less
-      - sass
-      - stylus
-      - sugarss
-      - supports-color
-      - terser
+      vitest: 0.29.2_ck7bzyzbhiuhyu6l53oypc6j6a
     dev: true
 
-  /@vitest/expect/0.28.5:
-    resolution: {integrity: sha512-gqTZwoUTwepwGIatnw4UKpQfnoyV0Z9Czn9+Lo2/jLIt4/AXLTn+oVZxlQ7Ng8bzcNkR+3DqLJ08kNr8jRmdNQ==}
+  /@vitest/expect/0.29.2:
+    resolution: {integrity: sha512-wjrdHB2ANTch3XKRhjWZN0UueFocH0cQbi2tR5Jtq60Nb3YOSmakjdAvUa2JFBu/o8Vjhj5cYbcMXkZxn1NzmA==}
     dependencies:
-      '@vitest/spy': 0.28.5
-      '@vitest/utils': 0.28.5
+      '@vitest/spy': 0.29.2
+      '@vitest/utils': 0.29.2
       chai: 4.3.7
     dev: true
 
-  /@vitest/runner/0.28.5:
-    resolution: {integrity: sha512-NKkHtLB+FGjpp5KmneQjTcPLWPTDfB7ie+MmF1PnUBf/tGe2OjGxWyB62ySYZ25EYp9krR5Bw0YPLS/VWh1QiA==}
+  /@vitest/runner/0.29.2:
+    resolution: {integrity: sha512-A1P65f5+6ru36AyHWORhuQBJrOOcmDuhzl5RsaMNFe2jEkoj0faEszQS4CtPU/LxUYVIazlUtZTY0OEZmyZBnA==}
     dependencies:
-      '@vitest/utils': 0.28.5
+      '@vitest/utils': 0.29.2
       p-limit: 4.0.0
       pathe: 1.1.0
     dev: true
 
-  /@vitest/spy/0.28.5:
-    resolution: {integrity: sha512-7if6rsHQr9zbmvxN7h+gGh2L9eIIErgf8nSKYDlg07HHimCxp4H6I/X/DPXktVPPLQfiZ1Cw2cbDIx9fSqDjGw==}
+  /@vitest/spy/0.29.2:
+    resolution: {integrity: sha512-Hc44ft5kaAytlGL2PyFwdAsufjbdOvHklwjNy/gy/saRbg9Kfkxfh+PklLm1H2Ib/p586RkQeNFKYuJInUssyw==}
     dependencies:
       tinyspy: 1.1.1
     dev: true
 
-  /@vitest/ui/0.28.5:
-    resolution: {integrity: sha512-hzzZzv38mH/LMFh54QEJpWFuGixZZBOD+C0fHU81d1lsvochPwNZhWJbuRJQNyZLSMZYCYW4hF6PpNQJXDHDmg==}
+  /@vitest/ui/0.29.2:
+    resolution: {integrity: sha512-GpCExCMptrS1z3Xf6kz35Xdvjc2eTBy9OIIwW3HjePVxw9Q++ZoEaIBVimRTTGzSe40XiAI/ZyR0H0Ya9brqLA==}
     dependencies:
       fast-glob: 3.2.12
       flatted: 3.2.7
@@ -1554,8 +1544,8 @@ packages:
       sirv: 2.0.2
     dev: true
 
-  /@vitest/utils/0.28.5:
-    resolution: {integrity: sha512-UyZdYwdULlOa4LTUSwZ+Paz7nBHGTT72jKwdFSV4IjHF1xsokp+CabMdhjvVhYwkLfO88ylJT46YMilnkSARZA==}
+  /@vitest/utils/0.29.2:
+    resolution: {integrity: sha512-F14/Uc+vCdclStS2KEoXJlOLAEyqRhnw0gM27iXw9bMTcyKRPJrQ+rlC6XZ125GIPvvKYMPpVxNhiou6PsEeYQ==}
     dependencies:
       cli-truncate: 3.1.0
       diff: 5.1.0
@@ -1661,8 +1651,8 @@ packages:
     resolution: {integrity: sha512-BHGyyGN3Q97EZx0taMQ+OLNuZcW3d37ZEVmEAyeoA9ERdGvm9Irc/0Fua8SNyOtV1w6BS4q25wbMzJujO9HIfQ==}
     dev: true
 
-  /@vue/test-utils/2.3.0:
-    resolution: {integrity: sha512-S8/9Z+B4VSsTUNtZtzS7J1TfxJbf10n+gcH9X8cASbG0Tp7qD6vqs/sUNlmpzk6i7+pP00ptauJp9rygyW89Ww==}
+  /@vue/test-utils/2.3.1:
+    resolution: {integrity: sha512-tRtHRPEETQSUrqXgAewNZHm5iypxDFxwenfdcvMRm1kbGo4bcqHb1XHHlsaIjoDbLkuE2NYiF8vBQDNYrzlrSA==}
     peerDependencies:
       vue: ^3.0.1
     dependencies:
@@ -1948,10 +1938,6 @@ packages:
       wcwidth: 1.0.1
     dev: true
 
-  /buffer-from/1.1.2:
-    resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
-    dev: true
-
   /busboy/1.6.0:
     resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==}
     engines: {node: '>=10.16.0'}
@@ -5003,13 +4989,6 @@ packages:
     engines: {node: '>=0.10.0'}
     dev: true
 
-  /source-map-support/0.5.21:
-    resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==}
-    dependencies:
-      buffer-from: 1.1.2
-      source-map: 0.6.1
-    dev: true
-
   /source-map/0.6.1:
     resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
     engines: {node: '>=0.10.0'}
@@ -5475,6 +5454,10 @@ packages:
     resolution: {integrity: sha512-LQc2s/ZDMaCN3QLpa+uzHUOQ7SdV0qgv3VBXOolQGXTaaZpIur6PwUclF5nN2hNkiTRcUugXd1zFOW3FLJ135Q==}
     dev: true
 
+  /ufo/1.1.1:
+    resolution: {integrity: sha512-MvlCc4GHrmZdAllBc0iUDowff36Q9Ndw/UzqmEKyrfSzokTd9ZCy1i+IIk5hrYKkjoYVQyNbrw7/F8XJ2rEwTg==}
+    dev: true
+
   /uglify-js/3.17.4:
     resolution: {integrity: sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==}
     engines: {node: '>=0.8.0'}
@@ -5598,8 +5581,8 @@ packages:
     engines: {node: '>= 0.10'}
     dev: true
 
-  /vite-node/0.28.5_@types+node@18.14.0:
-    resolution: {integrity: sha512-LmXb9saMGlrMZbXTvOveJKwMTBTNUH66c8rJnQ0ZPNX+myPEol64+szRzXtV5ORb0Hb/91yq+/D3oERoyAt6LA==}
+  /vite-node/0.29.2_@types+node@18.14.0:
+    resolution: {integrity: sha512-5oe1z6wzI3gkvc4yOBbDBbgpiWiApvuN4P55E8OI131JGrSuo4X3SOZrNmZYo4R8Zkze/dhi572blX0zc+6SdA==}
     engines: {node: '>=v14.16.0'}
     hasBin: true
     dependencies:
@@ -5608,8 +5591,6 @@ packages:
       mlly: 1.1.1
       pathe: 1.1.0
       picocolors: 1.0.0
-      source-map: 0.6.1
-      source-map-support: 0.5.21
       vite: 4.1.4_@types+node@18.14.0
     transitivePeerDependencies:
       - '@types/node'
@@ -5648,6 +5629,29 @@ packages:
       - supports-color
     dev: true
 
+  /vite-plugin-dts/2.1.0_vite@4.1.4:
+    resolution: {integrity: sha512-Vw0FdCuM3VLR4hTFHh0yMEzfwI7NyFvPIMFwvE+Q0t4qtoHIfYOP/JXs7nTnHuQk87FSjlhGeIJ1fLBcktgPgA==}
+    engines: {node: ^14.18.0 || >=16.0.0}
+    peerDependencies:
+      vite: '>=2.9.0'
+    dependencies:
+      '@babel/parser': 7.21.1
+      '@microsoft/api-extractor': 7.34.4
+      '@rollup/pluginutils': 5.0.2
+      '@rushstack/node-core-library': 3.55.2
+      debug: 4.3.4
+      fast-glob: 3.2.12
+      fs-extra: 10.1.0
+      kolorist: 1.7.0
+      magic-string: 0.29.0
+      ts-morph: 17.0.1
+      vite: 4.1.4
+    transitivePeerDependencies:
+      - '@types/node'
+      - rollup
+      - supports-color
+    dev: true
+
   /vite-plugin-glsl/1.1.2_vite@4.1.4:
     resolution: {integrity: sha512-zmXsfc1vn2MlYve9t3FAoWuhLyoCkNS1TuQL+TkXZL7tGmBjRErp10eNYxcse5tK9oUC5MyJpNc4ElpQnx8DoA==}
     engines: {node: '>= 16.15.1', npm: '>= 8.11.0'}
@@ -5660,8 +5664,8 @@ packages:
       - rollup
     dev: true
 
-  /vite-plugin-inspect/0.7.15_vite@4.1.4:
-    resolution: {integrity: sha512-oxeZCljacA/slhGFbDNlBqdhDU9fgdHL84i7Nz7DnaAIE7DhTiW2djanw3d/BKuZtduKUY82vRUQ4iaG917t2A==}
+  /vite-plugin-inspect/0.7.16_vite@4.1.4:
+    resolution: {integrity: sha512-WnyoicZ+mSQgrWoQdwrGydvlbfmlTKDVlMtub8RYCld3oXbC5kset3WmtgisrLmiDPobDvx2v7zUtPNQSySWXA==}
     engines: {node: '>=14'}
     peerDependencies:
       vite: ^3.1.0 || ^4.0.0
@@ -5672,7 +5676,7 @@ packages:
       fs-extra: 11.1.0
       kolorist: 1.7.0
       sirv: 2.0.2
-      ufo: 1.1.0
+      ufo: 1.1.1
       vite: 4.1.4
     transitivePeerDependencies:
       - rollup
@@ -5791,8 +5795,8 @@ packages:
       - terser
     dev: true
 
-  /vitest/0.28.5_7o7wrzczp3bjambnh5yw6wrpda:
-    resolution: {integrity: sha512-pyCQ+wcAOX7mKMcBNkzDwEHRGqQvHUl0XnoHR+3Pb1hytAHISgSxv9h0gUiSiYtISXUU3rMrKiKzFYDrI6ZIHA==}
+  /vitest/0.29.2_ck7bzyzbhiuhyu6l53oypc6j6a:
+    resolution: {integrity: sha512-ydK9IGbAvoY8wkg29DQ4ivcVviCaUi3ivuPKfZEVddMTenFHUfB8EEDXQV8+RasEk1ACFLgMUqAaDuQ/Nk+mQA==}
     engines: {node: '>=v14.16.0'}
     hasBin: true
     peerDependencies:
@@ -5816,11 +5820,11 @@ packages:
       '@types/chai': 4.3.4
       '@types/chai-subset': 1.3.3
       '@types/node': 18.14.0
-      '@vitest/expect': 0.28.5
-      '@vitest/runner': 0.28.5
-      '@vitest/spy': 0.28.5
-      '@vitest/ui': 0.28.5
-      '@vitest/utils': 0.28.5
+      '@vitest/expect': 0.29.2
+      '@vitest/runner': 0.29.2
+      '@vitest/spy': 0.29.2
+      '@vitest/ui': 0.29.2
+      '@vitest/utils': 0.29.2
       acorn: 8.8.2
       acorn-walk: 8.2.0
       cac: 6.7.14
@@ -5838,7 +5842,7 @@ packages:
       tinypool: 0.3.1
       tinyspy: 1.1.1
       vite: 4.1.4_@types+node@18.14.0
-      vite-node: 0.28.5_@types+node@18.14.0
+      vite-node: 0.29.2_@types+node@18.14.0
       why-is-node-running: 2.2.2
     transitivePeerDependencies:
       - less