[
  {
    "path": ".github/CODEOWNERS",
    "content": "* @alvarosabu"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "github: [tresjs, jaimetorrealba, alvarosabu]\nopen_collective: tresjs\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug.report.yml",
    "content": "name: Bug report 🐛\ndescription: Report an issue with Cientos\nlabels: [pending triage]\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        Thanks for taking the time to fill out this bug report!\n  - type: textarea\n    id: bug-description\n    attributes:\n      label: Describe the bug\n      description: A clear and concise description of what the bug is. If you intend to submit a PR for this issue, tell us in the description. Thanks!\n      placeholder: I am doing ... What I expect is ... What actually happening is ...\n    validations:\n      required: true\n  - type: input\n    id: reproduction\n    attributes:\n      label: Reproduction\n      description: Please provide a link via [stackblitz](https://stackblitz.com/edit/tresjs-basic?file=package.json,src%2Fcomponents%2FTheExperience.vue) or a link to a repo that can reproduce the problem you ran into. A [minimal reproduction](https://stackoverflow.com/help/minimal-reproducible-example) is required ([Why?](https://antfu.me/posts/why-reproductions-are-required)). If a report is vague (e.g. just a generic error message) and has no reproduction, it will receive a \"need reproduction\" label. If no reproduction is provided after 3 days, it will be auto-closed.\n      placeholder: Reproduction URL\n    validations:\n      required: true\n  - type: textarea\n    id: reproduction-steps\n    attributes:\n      label: Steps to reproduce\n      description: Please provide any reproduction steps that may need to be described. E.g. if it happens only when running the dev or build script make sure it's clear which one to use.\n      placeholder: Run `npm install` followed by `npm run dev`\n  - type: textarea\n    id: system-info\n    attributes:\n      label: System Info\n      description: Output of `npx envinfo --system --npmPackages '{vite,@tresjs/*, three, vue}' --binaries --browsers`\n      render: shell\n      placeholder: System, Binaries, Browsers\n  - type: dropdown\n    id: package-manager\n    attributes:\n      label: Used Package Manager\n      description: Select the used package manager\n      options:\n        - npm\n        - yarn\n        - pnpm\n    validations:\n      required: true\n  - type: checkboxes\n    id: terms\n    attributes:\n      label: Code of Conduct\n      description: By submitting this issue, please make sure you do the following\n      options:\n        - label: I agree to follow this project's [Code of Conduct](https://github.com/Tresjs/cientos/blob/main/CODE_OF_CONDUCT.md)\n          required: true\n        - label: Read the [Contributing Guidelines](https://github.com/Tresjs/cientos/blob/main/CONTRIBUTING.md).\n          required: true\n        - label: Read the [docs](https://cientos.tresjs.org/guide).\n          required: true\n        - label: Check that there isn't [already an issue](https://github.com/Tresjs/cientos/issues) that reports the same bug to avoid creating a duplicate.\n          required: true\n        - label: The provided reproduction is a [minimal reproducible example](https://stackoverflow.com/help/minimal-reproducible-example) of the bug.\n          required: true\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "blank_issues_enabled: false\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.yml",
    "content": "name: New feature proposal 🪐\ndescription: Propose a new feature to be added to Cientos\nlabels: [enhancement]\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        Thanks for your interest in the project and taking the time to fill out this feature report!\n  - type: textarea\n    id: feature-description\n    attributes:\n      label: Description\n      description: 'Clear and concise description of the problem. Please make the reason and usecases as detailed as possible. If you intend to submit a PR for this issue, tell us in the description. Thanks!'\n      placeholder: As a developer using TresJS I want [goal / wish] so that [benefit].\n    validations:\n      required: true\n  - type: textarea\n    id: suggested-solution\n    attributes:\n      label: Suggested solution\n      description: 'In module [xy] we could provide following implementation...'\n    validations:\n      required: true\n  - type: textarea\n    id: alternative\n    attributes:\n      label: Alternative\n      description: Clear and concise description of any alternative solutions or features you've considered.\n  - type: textarea\n    id: additional-context\n    attributes:\n      label: Additional context\n      description: Any other context or screenshots about the feature request here.\n  - type: checkboxes\n    id: checkboxes\n    attributes:\n      label: Validations\n      description: Before submitting the issue, please make sure you do the following\n      options:\n        - label: I agree to follow this project's [Code of Conduct](https://github.com/Tresjs/cientos/blob/main/CODE_OF_CONDUCT.md)\n          required: true\n        - label: Read the [Contributing Guidelines](https://github.com/Tresjs/cientos/blob/main/CONTRIBUTING.md).\n          required: true\n        - label: Read the [docs](https://cientos.tresjs.org/guide).\n          required: true\n        - label: Check that there isn't [already an issue](https://github.com/tresjs/cientos/issues) that reports the same bug to avoid creating a duplicate.\n          required: true\n"
  },
  {
    "path": ".github/workflows/lint-pr.yml",
    "content": "name: Lint PR\n\non:\n  pull_request_target:\n    types:\n      - opened\n      - edited\n      - synchronize\n\njobs:\n  main:\n    name: Validate PR title\n    runs-on: ubuntu-latest\n    steps:\n      - uses: amannn/action-semantic-pull-request@v5\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n"
  },
  {
    "path": ".github/workflows/lint.yml",
    "content": "name: Run linters\non: [push]\n\nenv:\n  PNPM_CACHE_FOLDER: .pnpm-store\n  HUSKY: 0 # Bypass husky commit hook for CI\n\njobs:\n  lint:\n    name: Lint\n    runs-on: ubuntu-24.04\n    strategy:\n      matrix:\n        node-version: [20]\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v4\n      - name: Setup pnpm\n        uses: pnpm/action-setup@v4\n      - name: Use Node.js ${{ matrix.node-version }}\n        uses: actions/setup-node@v4\n        with:\n          node-version: ${{ matrix.node-version }}\n          cache: pnpm\n      - name: Install dependencies\n        run: pnpm install\n      - name: Run Lint\n        run: pnpm run lint\n"
  },
  {
    "path": ".github/workflows/pkg.pr.new.yml",
    "content": "name: Publish Any Commit\non:\n  push:\n    branches:\n      - '**'\n    tags:\n      - '!**'\n\nenv:\n  PNPM_CACHE_FOLDER: .pnpm-store\n  HUSKY: 0 # Bypass husky commit hook for CI\n\npermissions: {}\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.event.number }}\n  cancel-in-progress: true\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        node-version: [20]\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v4\n\n      - run: npm i -g --force corepack && corepack enable\n      - uses: actions/setup-node@v4\n        with:\n          node-version: ${{ matrix.node-version }}\n          cache: pnpm\n      - name: Install dependencies\n        run: pnpm install\n      - name: Build\n        run: pnpm build\n      - run: pnpx pkg-pr-new publish --compact --pnpm\n"
  },
  {
    "path": ".gitignore",
    "content": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\npnpm-debug.log*\nlerna-debug.log*\n\nnode_modules\ndist\ndist-ssr\n*.local\n\n# Editor directories and files\n.vscode/*\n!.vscode/extensions.json\n.idea\n**/.DS_Store\n*.suo\n*.ntvs*\n*.njsproj\n*.sln\n*.sw?\nstats.html\ndocs/.vitepress/dist/\ndocs/.vitepress/cache/\ndocs/.vitepress/.temp/\ndocs/components.d.ts\nplayground/components.d.ts\n"
  },
  {
    "path": ".npmrc",
    "content": "shamefully-hoist=true"
  },
  {
    "path": ".release-it.json",
    "content": "{\n  \"git\": {\n    \"commitMessage\": \"chore: release v${version}\"\n  },\n  \"github\": {\n    \"release\": true,\n    \"releaseName\": \"v${version}\"\n  },\n  \"plugins\": {\n    \"@release-it/conventional-changelog\": {\n      \"preset\": \"conventionalcommits\",\n      \"infile\": \"CHANGELOG.md\"\n    }\n  },\n  \"hooks\": {\n    \"before:init\": [\"pnpm run lint\"],\n    \"after:bump\": \"pnpm run build\",\n    \"after:git:release\": \"echo After git push, before github release\",\n    \"after:release\": \"echo Successfully released ${name} v${version} to ${repo.repository}.\"\n  }\n}\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Changelog\n\n## [5.0.0](https://github.com/Tresjs/cientos/compare/4.3.1...5.0.0) (2025-09-20)\n\n### Features\n\n* release v5 ([#563](https://github.com/Tresjs/cientos/issues/563)) ([28808b5](https://github.com/Tresjs/cientos/commit/28808b58cfbcfdc57d0f1fe0656da9a8d3e4bcdb)), closes [#543](https://github.com/Tresjs/cientos/issues/543)\n\n### Bug Fixes\n\n* precipitation speed ([#643](https://github.com/Tresjs/cientos/issues/643)) ([8958ecc](https://github.com/Tresjs/cientos/commit/8958eccb30ed6537eaa84a2221ff7e39a158bd88))\n\n## [5.0.0-rc.0](https://github.com/Tresjs/cientos/compare/5.0.0-alpha.1...5.0.0-rc.0) (2025-09-20)\n\n## [5.0.0-alpha.1](https://github.com/Tresjs/cientos/compare/5.0.0-alpha.0...5.0.0-alpha.1) (2025-09-06)\n\n### Features\n\n* enhance `useAnimations` composable with manual update option ([#637](https://github.com/Tresjs/cientos/issues/637)) ([b2b60e6](https://github.com/Tresjs/cientos/commit/b2b60e67aaa8d62012cf67f030acdb7c08c56a9a))\n\n## [5.0.0-alpha.0](https://github.com/Tresjs/cientos/compare/5.0.0-next.7...5.0.0-alpha.0) (2025-08-30)\n\n### Features\n\n* set peer @tresjs/core to 5.0.0 and alpha, updated dev deps ([#641](https://github.com/Tresjs/cientos/issues/641)) ([48817fd](https://github.com/Tresjs/cientos/commit/48817fdd092fb8b6658245160b6cacfac3cf2f3d))\n\n## [5.0.0-next.7](https://github.com/Tresjs/cientos/compare/5.0.0-next.6...5.0.0-next.7) (2025-08-11)\n\n### Features\n\n* add `traverse` option to model loaders ([#635](https://github.com/Tresjs/cientos/issues/635)) ([421350f](https://github.com/Tresjs/cientos/commit/421350fc7c3fca0806f61f21fe8bc765bf7d4589))\n\n### Bug Fixes\n\n* enhance audio and sprite loading logic ([4319fa9](https://github.com/Tresjs/cientos/commit/4319fa94e2578d5ed37ad381854984deeae9d17e))\n\n## [5.0.0-next.6](https://github.com/Tresjs/cientos/compare/5.0.0-next.5...5.0.0-next.6) (2025-07-31)\n\n### Bug Fixes\n\n* **orbit-controls:** added key to force re-render ([c93f6c1](https://github.com/Tresjs/cientos/commit/c93f6c18750dd1a3499ec85c89e9bd567edc6ae5))\n\n## [5.0.0-next.5](https://github.com/Tresjs/cientos/compare/5.0.0-next.4...5.0.0-next.5) (2025-07-08)\n\n### ⚠ BREAKING CHANGES\n\n* useFBX no longer returns the plain obj, it now returns an object with reactive data (state, isLoading, error) and a load method.\n\n- Updated `vue` to version `3.5.17` and `three` to version `0.178.0` in `package.json` for enhanced compatibility and features.\n- Upgraded `@vitejs/plugin-vue` to version `6.0.0` and `vite` to version `7.0.2` to leverage the latest improvements in the build process.\n- Enhanced the `useFBX` composable to provide a reactive state for loading FBX models, allowing for better handling of model properties and loading states.\n- Improved the `FBXModel` component to support shadow properties and added a new demo for better visualization of FBX model loading.\n- Updated documentation to reflect changes in the FBX model loading process and added examples for better clarity.\n\n* fix(TheModel.vue): remove unused type import for improved clarity\n\n- Removed the unused import of `Group` from TheModel.vue to enhance code clarity and maintainability. This change aligns with the ongoing effort to streamline type imports and improve type safety across the codebase.\n\n* feat: expose model state in useFBX and useGLTF components\n\n- Added `defineExpose` to both `useFBX` and `useGLTF` components to expose the reactive model state, allowing for better integration and access to the model instance in parent components.\n- This enhancement improves the usability of the components by providing a direct reference to the model state, facilitating more dynamic interactions and updates.\n\n* fix(useFBX): add missing comma in defineExpose for model instance\n\n- Added a missing comma in the `defineExpose` call within the `useFBX` component to ensure proper syntax and prevent potential runtime errors. This minor fix enhances code clarity and maintains consistency in the component's structure.\n\n### Features\n\n* refactor useFBX ([#628](https://github.com/Tresjs/cientos/issues/628)) ([d59ef26](https://github.com/Tresjs/cientos/commit/d59ef26ff9e1924c12188f458324b83f72196f96))\n\n## [5.0.0-next.4](https://github.com/Tresjs/cientos/compare/5.0.0-next.3...5.0.0-next.4) (2025-06-30)\n\n### Bug Fixes\n\n* create a local raycast for the HTML component ([#627](https://github.com/Tresjs/cientos/issues/627)) ([614505f](https://github.com/Tresjs/cientos/commit/614505fd84381919308136d510ffb69b805a5038))\n* **transform-controls:** use correct emit on mouse up ([#625](https://github.com/Tresjs/cientos/issues/625)) ([f04a63c](https://github.com/Tresjs/cientos/commit/f04a63cab66b9e0cc0fc17f7622944999c417787))\n\n## [5.0.0-next.3](https://github.com/Tresjs/cientos/compare/5.0.0-next.2...5.0.0-next.3) (2025-06-22)\n\n### Bug Fixes\n\n* typescript issues ([#624](https://github.com/Tresjs/cientos/issues/624)) ([3c1640e](https://github.com/Tresjs/cientos/commit/3c1640e512cd77f0f980a63d1aa9414d4cc4d608))\n\n## [5.0.0-next.2](https://github.com/Tresjs/cientos/compare/5.0.0-next.1...5.0.0-next.2) (2025-06-15)\n\n### Bug Fixes\n\n* adapt to renderer.isntance no longer being shallowRef ([430534a](https://github.com/Tresjs/cientos/commit/430534a40d37e44dc026facfe9a4faac461decab))\n* remove unused type import in MouseParallax.vue ([0899ecf](https://github.com/Tresjs/cientos/commit/0899ecfc0e02a7ded4b1368d5ad22dc352b1f1ce))\n* type issues from v5 ([bd0e0c6](https://github.com/Tresjs/cientos/commit/bd0e0c6abbe2616fb73d44171716fa54c2ac54b9))\n\n## [5.0.0-next.1](https://github.com/Tresjs/cientos/compare/5.0.0-next.0...5.0.0-next.1) (2025-06-15)\n\n## [5.0.0-next.0](https://github.com/Tresjs/cientos/compare/4.3.1...5.0.0-next.0) (2025-06-06)\n\n### ⚠ BREAKING CHANGES\n\n* cientos  is now ESM only\n\n- Added 'es' format to the Vite configuration for better module compatibility.\n- Removed the UMD globals section from the output configuration as it is no longer necessary, streamlining the build process.\n* useGLTF no longer returns the plain obj, it now returns an object with reactive data (state, isLoading, error) and a load method.\n\n- Refactored GLTF loading in components to use the updated `useGLTF` composable, improving state management and performance.\n- Removed unnecessary `Suspense` wrappers in demo components for cleaner rendering.\n- Added new demo components for showcasing GLTF model loading with DRACO compression.\n- Updated documentation to reflect changes in GLTF model usage.\n\n* fix: update import syntax and clean up unused code\n\n- Changed import statement for `TresObject` in `gltf-model.md` to use the correct TypeScript syntax.\n- Removed unused imports in `use-gltf/index.vue` for cleaner code.\n- Added ESLint directive to disable console warnings in `TheModel.vue` for development purposes.\n\n* docs: update useGLTF implementation and clean up components\n\n- Refactored components to utilize the new `useGLTF` structure, replacing direct access to nodes with reactive state management.\n- Removed unused imports and commented-out code for improved clarity and maintainability.\n- Updated documentation references to reflect changes in component usage and structure.\n\n* feat: adapt useAnimations to new useAsyncState loader's model\n\n- Added a new demo page for `use-animations` showcasing the animated GLTF model.\n- Refactored the `useAnimations` composable to support reactive animations using `MaybeRef`.\n- Updated the `TheModel.vue` component to utilize the new reactive state for animations.\n- Enhanced the main demo layout with `TresCanvas`, `OrbitControls`, and lighting for improved visualization.\n\n* chore: update @tresjs/core dependency to version 5.0.0-next.0\n\n- Changed the dependency for @tresjs/core in package.json and playground/vue/package.json to the stable version 5.0.0-next.0 from a previous URL reference.\n- Updated pnpm-lock.yaml to reflect the new version of @tresjs/core across all relevant sections.\n- Adjusted the useGLTF implementation in documentation to align with the new state management approach.\n\n### Features\n\n* 608 drop umd support ([#622](https://github.com/Tresjs/cientos/issues/622)) ([14afe95](https://github.com/Tresjs/cientos/commit/14afe95c3f0c1ae5fb5b6cc4b57d3f86b46f0f4b))\n* 609-refactor-usegltf ([#610](https://github.com/Tresjs/cientos/issues/610)) ([13943b0](https://github.com/Tresjs/cientos/commit/13943b0401a7f1d10723ae01659c6d8b50f04310))\n* 611 move cores usetexture to cientos ([#617](https://github.com/Tresjs/cientos/issues/617)) ([430377d](https://github.com/Tresjs/cientos/commit/430377d8d8a1b5e902167bc210e4f48b1141c300))\n* 615-adapt-camera-dependant-abstractions-to-core-v5-camera-changes ([#621](https://github.com/Tresjs/cientos/issues/621)) ([682d38f](https://github.com/Tresjs/cientos/commit/682d38f2a6366918a77aa7e8c312484582c62b8c))\n* 616-adapt-code-to-core-ctx-renderer-state-breaking-change ([#620](https://github.com/Tresjs/cientos/issues/620)) ([2ae981f](https://github.com/Tresjs/cientos/commit/2ae981f42fa6a76fad2202236b49c28f395dfb29))\n* **AccumulativeShadows:** add component, demo, docs ([#558](https://github.com/Tresjs/cientos/issues/558)) ([7e6b8d0](https://github.com/Tresjs/cientos/commit/7e6b8d0dbbe2f1f0500072815c86c2cf0c559a58))\n* **Bounds:** add component, demo, docs ([#408](https://github.com/Tresjs/cientos/issues/408)) ([#568](https://github.com/Tresjs/cientos/issues/568)) ([592ec68](https://github.com/Tresjs/cientos/commit/592ec68de83fcd5a62523b32b96ade825437ea68))\n* **CircleShadow:** add component, demo, docs ([#549](https://github.com/Tresjs/cientos/issues/549)) ([c0c1bcc](https://github.com/Tresjs/cientos/commit/c0c1bcc15743f0c93f8908b9e29d2555a4c79c85))\n* **CubicBezierLine:** add component, demo, docs ([#546](https://github.com/Tresjs/cientos/issues/546)) ([99c3a60](https://github.com/Tresjs/cientos/commit/99c3a60d5e99d25dcb65da1f04ccd4ce0499d919))\n* **Helper:** add component, demo, docs ([#543](https://github.com/Tresjs/cientos/issues/543)) ([63535a2](https://github.com/Tresjs/cientos/commit/63535a24689c5fb1353b26d2add7f899a74ada37))\n* **LOD:** add component, playground, docs ([#524](https://github.com/Tresjs/cientos/issues/524)) ([ef6438c](https://github.com/Tresjs/cientos/commit/ef6438c46d43d83ee6bf5d1b4e36a9a7e69c8297))\n* **MarchingCubes:** add component, demo, docs ([#553](https://github.com/Tresjs/cientos/issues/553)) ([2ebc1e6](https://github.com/Tresjs/cientos/commit/2ebc1e6c75107d6914b4ad3b7e8488b06f5db2f6))\n* **PointMaterial:** add component, demo, docs ([#545](https://github.com/Tresjs/cientos/issues/545)) ([4528f64](https://github.com/Tresjs/cientos/commit/4528f64063d2f9cc903cc9f21c8c09ef792b919a))\n* **QuadraticBezierLine:** add component, demo, docs ([#548](https://github.com/Tresjs/cientos/issues/548)) ([4a9f006](https://github.com/Tresjs/cientos/commit/4a9f006d5c318781d52f6e943b7c4f342a077667))\n* **ScreenQuad:** add component, playground, docs ([#530](https://github.com/Tresjs/cientos/issues/530)) ([34a3db5](https://github.com/Tresjs/cientos/commit/34a3db5162d084f9fc3db82885a271a1a8c31424))\n* **Stage:** add component, demo, docs ([#572](https://github.com/Tresjs/cientos/issues/572)) ([9db8c78](https://github.com/Tresjs/cientos/commit/9db8c782d434a33c64663f313bc289199281f4eb))\n* **useIntersect:** add function, demo, docs ([#550](https://github.com/Tresjs/cientos/issues/550)) ([b0ba621](https://github.com/Tresjs/cientos/commit/b0ba62159c4ae9b2e51f85dcad5c9fe8d03ff6e8))\n\n### Bug Fixes\n\n* fixes to next components and docs ([#586](https://github.com/Tresjs/cientos/issues/586)) ([bc54a1d](https://github.com/Tresjs/cientos/commit/bc54a1da5aa8e0f7c9852713c01d405b9f5eff29))\n* return nodes and materials computed directly ([#612](https://github.com/Tresjs/cientos/issues/612)) ([4fe342a](https://github.com/Tresjs/cientos/commit/4fe342aeb34741ce828ba1bed26279d00f9be9e7))\n* rollback to previous use tres usage ([#623](https://github.com/Tresjs/cientos/issues/623)) ([cfa38b1](https://github.com/Tresjs/cientos/commit/cfa38b1c88421430ab5204ae943443cc50e44dfe))\n\n## [4.3.1](https://github.com/Tresjs/cientos/compare/4.3.0...4.3.1) (2025-05-16)\n\n### Bug Fixes\n\n* **deps:** update @tresjs/core and @types/three to latest versions ([#619](https://github.com/Tresjs/cientos/issues/619)) ([9a94785](https://github.com/Tresjs/cientos/commit/9a94785f8242b10df3a1c579e54f04814716552a))\n\n## [4.3.0](https://github.com/Tresjs/cientos/compare/4.2.0...4.3.0) (2025-03-25)\n\n### Features\n\n* **environment:** enhance environment and background props ([#590](https://github.com/Tresjs/cientos/issues/590)) ([7e96136](https://github.com/Tresjs/cientos/commit/7e96136ad4f9da046ad14eb31a69a7ff67649010))\n\n## [4.2.0](https://github.com/Tresjs/cientos/compare/4.1.1...4.2.0) (2025-03-07)\n\n### Features\n\n* **OrbitControls:** add mouseButtons prop to customize mouse interactions ([#603](https://github.com/Tresjs/cientos/issues/603)) ([5a7c2ca](https://github.com/Tresjs/cientos/commit/5a7c2cacb67db61a2fe54ed485703735ba167e5f))\n\n## [4.1.1](https://github.com/Tresjs/cientos/compare/4.1.0...4.1.1) (2025-03-05)\n\n### Bug Fixes\n\n* remove will-change that makes Html components blurry ([#602](https://github.com/Tresjs/cientos/issues/602)) ([2b50296](https://github.com/Tresjs/cientos/commit/2b50296e5d4b141d072319872be6988aec984c61))\n* update html on camera dolly zoom ([#600](https://github.com/Tresjs/cientos/issues/600)) ([e5628f2](https://github.com/Tresjs/cientos/commit/e5628f2073cc7d7f6fbb15bcabe4571dae92f1df))\n\n## [4.1.0](https://github.com/Tresjs/cientos/compare/4.0.3...4.1.0) (2025-01-17)\n\n### Features\n\n* **Align:** add component, demo, docs ([#544](https://github.com/Tresjs/cientos/issues/544)) ([e3ee52c](https://github.com/Tresjs/cientos/commit/e3ee52c97c769935e7144c6ca423427cf93447a3))\n* **Billboard:** add component, playground, docs ([#527](https://github.com/Tresjs/cientos/issues/527)) ([418e6ae](https://github.com/Tresjs/cientos/commit/418e6ae0d1d06fb689a5e583ff200d2f4de54848))\n* **CubeCamera:** add component, demo, docs ([#537](https://github.com/Tresjs/cientos/issues/537)) ([02ed01c](https://github.com/Tresjs/cientos/commit/02ed01ca14d1f154c888ed9eeb7e95d63ad225a1))\n* edges ([#390](https://github.com/Tresjs/cientos/issues/390)) ([60c200d](https://github.com/Tresjs/cientos/commit/60c200d19d7f82781632576c22e3b15ea118ac5c))\n* **gradientTexture:** add component, demo, docs ([#531](https://github.com/Tresjs/cientos/issues/531)) ([58d0fdb](https://github.com/Tresjs/cientos/commit/58d0fdb582e0c9ca464648ece256094cda1f427f))\n* **Grid:** add component, demo, docs ([#540](https://github.com/Tresjs/cientos/issues/540)) ([096ab5d](https://github.com/Tresjs/cientos/commit/096ab5d76b5dc9760528765fc2aebbf548affb9a))\n* **Image:** add component, playground, docs ([#529](https://github.com/Tresjs/cientos/issues/529)) ([ad916a2](https://github.com/Tresjs/cientos/commit/ad916a2e58f1fdb4409c5ab9fcdfa9cabff418b3))\n* **Mask:** add component, demo, docs ([#552](https://github.com/Tresjs/cientos/issues/552)) ([0fb8952](https://github.com/Tresjs/cientos/commit/0fb895295f00f46e118b0e8b740834379a1d53d3))\n* **MeshDiscardMaterial:** add component, playground, docs ([#525](https://github.com/Tresjs/cientos/issues/525)) ([7a23019](https://github.com/Tresjs/cientos/commit/7a23019c0cefb9c16954c7224369614748da06b9))\n* **Outline:** add component, demo, docs ([#532](https://github.com/Tresjs/cientos/issues/532)) ([5bae4de](https://github.com/Tresjs/cientos/commit/5bae4de1005cda00d7ad6ecbb25a96e64441b78f))\n* **ScreenSizer:** add component, playground, docs ([#535](https://github.com/Tresjs/cientos/issues/535)) ([ee5af96](https://github.com/Tresjs/cientos/commit/ee5af96cebb12487fa519ce638624bdd375d37be))\n* **ScreenSpace:** add component, demo, docs ([#536](https://github.com/Tresjs/cientos/issues/536)) ([e43f112](https://github.com/Tresjs/cientos/commit/e43f1122248fbd35d00b590fe165c5ac57246d25))\n* **SoftShadows:** add component, demo, docs ([#541](https://github.com/Tresjs/cientos/issues/541)) ([e71cdad](https://github.com/Tresjs/cientos/commit/e71cdad6c9b9b0a9a65c9fce838498b373711875))\n\n### Bug Fixes\n\n* 581 environment lightformers are not working ([#584](https://github.com/Tresjs/cientos/issues/584)) ([653a5df](https://github.com/Tresjs/cientos/commit/653a5df0468c984f307e4b3efd4bdccbaaceef6d))\n* build dts error TS7056 ([#521](https://github.com/Tresjs/cientos/issues/521)) ([c16c6e5](https://github.com/Tresjs/cientos/commit/c16c6e594f4a0662739343181ad8103644f8514d))\n* **deps:** update dependency @tresjs/core to v4.3.0 ([#503](https://github.com/Tresjs/cientos/issues/503)) ([83fa2bf](https://github.com/Tresjs/cientos/commit/83fa2bf1c61e8d62cccd1772fccc251c3109c984))\n* **deps:** update dependency vue-router to v4.4.5 ([#488](https://github.com/Tresjs/cientos/issues/488)) ([0840b88](https://github.com/Tresjs/cientos/commit/0840b885dd960eeeb10077d15f606a2644412474))\n* instance properties and fix demo ([#561](https://github.com/Tresjs/cientos/issues/561)) ([f0fb337](https://github.com/Tresjs/cientos/commit/f0fb337d3f3900485708839898bba797f8a6f7ab))\n* **KeyboardControls:** support non-qwerty keyboards ([#573](https://github.com/Tresjs/cientos/issues/573)) ([#574](https://github.com/Tresjs/cientos/issues/574)) ([efdde6d](https://github.com/Tresjs/cientos/commit/efdde6de32f32cbe0a8b69f7df0a701b4fc333a6))\n* **MeshReflectionMaterial:** remove unneeded material.onBeforeRender ([#534](https://github.com/Tresjs/cientos/issues/534)) ([f622324](https://github.com/Tresjs/cientos/commit/f6223249e3d5a95e7aa76a782125a535d4dd69df))\n* typescript build issues ([#578](https://github.com/Tresjs/cientos/issues/578)) ([09584be](https://github.com/Tresjs/cientos/commit/09584be48705d24a4eaf89655ac78138fc95108d))\n* update core version with patch ([#508](https://github.com/Tresjs/cientos/issues/508)) ([cbae8ee](https://github.com/Tresjs/cientos/commit/cbae8ee2caac2d125bff4e944986babe734680af))\n\n## [4.0.3](https://github.com/Tresjs/cientos/compare/4.0.2...4.0.3) (2024-10-04)\n\n\n### Bug Fixes\n\n* **deps:** update dependency @tresjs/core to v4.2.10 ([#479](https://github.com/Tresjs/cientos/issues/479)) ([fb3026a](https://github.com/Tresjs/cientos/commit/fb3026aa2f54b2f388f1a074714ac46b10f3af81))\n* discrepancy between param enableDamping in OrbitControl ([#486](https://github.com/Tresjs/cientos/issues/486)) ([97a224c](https://github.com/Tresjs/cientos/commit/97a224c32e5aedf472c77e43dd6c426fc09a1f45))\n\n## [4.0.2](https://github.com/Tresjs/cientos/compare/4.0.1...4.0.2) (2024-08-30)\n\n\n### Bug Fixes\n\n* **useGltf:** use-loader fix for gltf with textures ([#480](https://github.com/Tresjs/cientos/issues/480)) ([f1f983f](https://github.com/Tresjs/cientos/commit/f1f983f94cea8f4cd4bef451c768ff175ddd4f00))\n\n## [4.0.1](https://github.com/Tresjs/cientos/compare/4.0.0...4.0.1) (2024-08-30)\n\n\n### Bug Fixes\n\n* adapt to changes on useloader for Cube Textures ([#476](https://github.com/Tresjs/cientos/issues/476)) ([3641dc6](https://github.com/Tresjs/cientos/commit/3641dc6db3a663b5d28d2e7899f26faf244959ce))\n* **deps:** update dependency @tresjs/core to v4.2.7 ([#466](https://github.com/Tresjs/cientos/issues/466)) ([0596353](https://github.com/Tresjs/cientos/commit/0596353a1d4aed2b984fac58442530279375e1a9))\n\n## [4.0.0](https://github.com/Tresjs/cientos/compare/3.9.0...4.0.0) (2024-08-20)\n\n\n### Features\n\n* Add cylinder component ([9e17559](https://github.com/Tresjs/cientos/commit/9e17559fc98066db79b02b7ea0c98ae3037ac906))\n* V4 ([#420](https://github.com/Tresjs/cientos/issues/420)) ([0cdd58e](https://github.com/Tresjs/cientos/commit/0cdd58ee0b8f1e086899a3efb7ad93575b117ccc)), closes [#425](https://github.com/Tresjs/cientos/issues/425) [#439](https://github.com/Tresjs/cientos/issues/439) [#435](https://github.com/Tresjs/cientos/issues/435) [#441](https://github.com/Tresjs/cientos/issues/441) [#436](https://github.com/Tresjs/cientos/issues/436) [#428](https://github.com/Tresjs/cientos/issues/428)\n\n\n### Bug Fixes\n\n* **SkyDemo:** value.value -> value ([82fe77b](https://github.com/Tresjs/cientos/commit/82fe77b4dc11fd23b47e40bc33a843dc69cf017f))\n* vue attrs hyphenation issues ([4f9b61b](https://github.com/Tresjs/cientos/commit/4f9b61b954a916d8f8880798f06c03b79092896b))\n\n## [4.0.0-rc.2](https://github.com/Tresjs/cientos/compare/4.0.0-rc.1...4.0.0-rc.2) (2024-07-26)\n\n## [4.0.0-rc.1](https://github.com/Tresjs/cientos/compare/4.0.0-rc.0...4.0.0-rc.1) (2024-07-25)\n\n\n### Features\n\n* **fbo:** add autoRender flag as an option to useFBO ([#458](https://github.com/Tresjs/cientos/issues/458)) ([ddcd4ac](https://github.com/Tresjs/cientos/commit/ddcd4ac36cfd5b5cbb06e967878a9468b390a17c))\n\n## [4.0.0-rc.0](https://github.com/Tresjs/cientos/compare/4.0.0-next.1...4.0.0-rc.0) (2024-07-24)\n\n\n### Features\n\n* **Sparkles:** invalidate on update ([#446](https://github.com/Tresjs/cientos/issues/446)) ([cbfd226](https://github.com/Tresjs/cientos/commit/cbfd226b94fb363f3a59a735365c679e8142420f))\n\n\n### Bug Fixes\n\n* reimplement ContactShadows for v4 ([#449](https://github.com/Tresjs/cientos/issues/449)) ([d71c328](https://github.com/Tresjs/cientos/commit/d71c328969da64beee05088ced05bd7b632d6f31))\n* update to core v4.2.2 to remove warning on invalidation ([42afa6e](https://github.com/Tresjs/cientos/commit/42afa6e67962796d2ce076a29917262f9ca09ea5))\n\n## [4.0.0-next.1](https://github.com/Tresjs/cientos/compare/3.9.0...4.0.0-next.1) (2024-07-17)\n\n\n### ⚠ BREAKING CHANGES\n\n* **MeshReflectionMaterial:** add features/docs, reorganize\n\n### Features\n\n* 423 enable on demand render mode usage ([#436](https://github.com/Tresjs/cientos/issues/436)) ([b3eef40](https://github.com/Tresjs/cientos/commit/b3eef40430d23e2ba6c5a195c0cf510c0bc54ce9))\n* **AnimatedSprite:** add asSprite prop ([7a14b55](https://github.com/Tresjs/cientos/commit/7a14b5592d78f57785d04bd1484a35e501b7cceb))\n* **AnimatedSprite:** dispose texture onUnmounted ([18d6904](https://github.com/Tresjs/cientos/commit/18d6904570cc34ca9c3e64e6b42ec5c639a6e885))\n* **AnimatedSprite:** remove explicit click event ([042c350](https://github.com/Tresjs/cientos/commit/042c350883aec53bdf0331cc4b3378e06d87fb88))\n* **AnimatedSprite:** remove unnecessary Suspense ([082d695](https://github.com/Tresjs/cientos/commit/082d695f1a6843a8fa5edcd8e6c32ec8530a03a9))\n* **app:** 421 Update components to use useLoop instead of useRenderLoop ([ad3b290](https://github.com/Tresjs/cientos/commit/ad3b290c4afb3adf5bf36ccf02d08ea1beb98bc8))\n* **app:** Add the option for x and y in mouseparallax component ([#444](https://github.com/Tresjs/cientos/issues/444)) ([12d5834](https://github.com/Tresjs/cientos/commit/12d5834becba2cdfc26300fd5bf1ec1f9e26afe3))\n* re-remove tweakpane ([#425](https://github.com/Tresjs/cientos/issues/425)) ([72284ce](https://github.com/Tresjs/cientos/commit/72284ce2e0e378d353b3573a6216ad6f6dcd4425))\n* update to core v4.2 ([14b30f9](https://github.com/Tresjs/cientos/commit/14b30f99282ed3cb1d21cbdf31e672867d79f27c))\n\n\n### Bug Fixes\n\n* **Lensflare demo:** add camera [#435](https://github.com/Tresjs/cientos/issues/435) ([#441](https://github.com/Tresjs/cientos/issues/441)) ([981de57](https://github.com/Tresjs/cientos/commit/981de572c97183b8d2070925daa8209d2fa6b55e))\n* **MeshReflectionMaterial:** add features/docs, reorganize ([58703e3](https://github.com/Tresjs/cientos/commit/58703e362bbe731a56b7ce903160df13513ec18a))\n* remove hardcoded speed number, that setting at 0 doesn't stop the effect ([e67f3a2](https://github.com/Tresjs/cientos/commit/e67f3a295025ca1bfb1c0f664ceccefac389e0af))\n* **SkyDemo:** value.value -> value ([82fe77b](https://github.com/Tresjs/cientos/commit/82fe77b4dc11fd23b47e40bc33a843dc69cf017f))\n* **types:** fixed types generics for `useGLTF` ([#448](https://github.com/Tresjs/cientos/issues/448)) ([62a9bcc](https://github.com/Tresjs/cientos/commit/62a9bcc2d4490c7493667c3316441b5363cb42fc))\n* uncomment section ([fac2253](https://github.com/Tresjs/cientos/commit/fac22534818a15d49f631b790185f4f1266c7339))\n* vue attrs hyphenation issues ([4f9b61b](https://github.com/Tresjs/cientos/commit/4f9b61b954a916d8f8880798f06c03b79092896b))\n\n## [4.0.0-next.0](https://github.com/Tresjs/cientos/compare/3.9.0...4.0.0-next.1) (2024-03-27)\n\n\n### ⚠ BREAKING CHANGES\n\n* **app:** 349 Remove directives from cientos\n* **app:** 227 Change the keyboardcontrols implementation\n\n### Features\n\n* add arrow keys support ([39e2094](https://github.com/Tresjs/cientos/commit/39e2094338ba37613b189e7d593ecc2b0a35680b))\n* **AnimatedSprite:** add AnimatedSprite, playground, docs ([d6ea81b](https://github.com/Tresjs/cientos/commit/d6ea81b5540c2f4bf0f233e269ed98992ee8a551))\n* **AnimatedSprite:** allow [numCols, numRows] as atlas prop ([3309d9c](https://github.com/Tresjs/cientos/commit/3309d9c24ee1d006b41bdeaa29eac7c8f9658342))\n* **AnimatedSprite:** always emit last frame name on loop and on end ([ed16136](https://github.com/Tresjs/cientos/commit/ed16136a84143396ae8accc327429c1ef1fbdd1b))\n* **AnimatedSprite:** change default fps ([44831a4](https://github.com/Tresjs/cientos/commit/44831a492e6a881061b9a113d1a627026b172056))\n* **app:** 227 Change the keyboardcontrols implementation ([fed0f86](https://github.com/Tresjs/cientos/commit/fed0f86b3c92aa8ea86be0e6193e1639d421bcc2))\n* **app:** 227 Final details, ready to go ([6f06213](https://github.com/Tresjs/cientos/commit/6f06213d92f9b389c3d1fca377002ae0b060c87b))\n\n\n### Bug Fixes\n\n* **AnimatedSprite:** return nullFrame animation if requested animation not found ([453819e](https://github.com/Tresjs/cientos/commit/453819e0237b58177a34bbeee0af4ce44252195c))\n* **Atlas:** add missing argument to function call ([e6b147e](https://github.com/Tresjs/cientos/commit/e6b147e45520238e8fd467863972af8fe8f8ec37))\n\n\n### Code Refactoring\n\n* **app:** 349 Remove directives from cientos ([8fc4cd5](https://github.com/Tresjs/cientos/commit/8fc4cd582ba85cc09e000627449622e8861ec76a))\n\n## [3.9.0](https://github.com/Tresjs/cientos/compare/3.8.0...3.9.0) (2024-05-07)\n\n### Features\n* add `local` props ([b9192fb](https://github.com/Tresjs/cientos/commit/b9192fb3c5ac617495866ad1df23a93a1068afbd))\n* add camera recognition for default props setup ([c8ebba0](https://github.com/Tresjs/cientos/commit/c8ebba03b72bdf45bd1927aeb953911269cb4bc1))\n* **app:** 252 adding ocean component ([7efb293](https://github.com/Tresjs/cientos/commit/7efb29300a5cda624801316e6bc4f33a88e8de04))\n* **app:** 252 Renamed as ocean, add sky support ([473bac6](https://github.com/Tresjs/cientos/commit/473bac61d9831b9334f4ba78b0d4ab979b7b167f))\n* **app:** Add holographic material to cientos ([f0f4eab](https://github.com/Tresjs/cientos/commit/f0f4eabdda380c912b4e3078ac2eddd7c7643edb))\n* **app:** Add RoundedBox component ([8b6cb67](https://github.com/Tresjs/cientos/commit/8b6cb67b686bf242aa6e96c3b68af535ddb944d1))\n* **cientos/positional-audio:** add positional audio component ([39c334c](https://github.com/Tresjs/cientos/commit/39c334cfeb592ce512c540d8d10fc71b771cacf9))\n* **cientos/positional-audio:** adding more logic and examples for playground ([73c94de](https://github.com/Tresjs/cientos/commit/73c94deb9bc3f2413f17e4ba7124ece2493cea47))\n* **cientos/positional-audio:** delete medias, modifications doc ([ae34177](https://github.com/Tresjs/cientos/commit/ae3417733c8092a83f1ede61ec4b3bfbc4cd61b8))\n* **cientos/positional-audio:** demo clean ([7bc1b61](https://github.com/Tresjs/cientos/commit/7bc1b61c7cb55a78e9fd9b19406cca0508c18643))\n* **cientos/positional-audio:** documentation v1, main example v1 ([bb68bda](https://github.com/Tresjs/cientos/commit/bb68bda3cf1a9b1a042ea388264669879511b4fb))\n* **cientos/positional-audio:** fix issues async, add gui example doc ([65c4c17](https://github.com/Tresjs/cientos/commit/65c4c17a9ce9b24710a5d5895334677e46b1a9a1))\n* **cientos/positional-audio:** fix lint issue, wip doc ([4e2b5fb](https://github.com/Tresjs/cientos/commit/4e2b5fbe0991d06391a02f7de1ab10d425f3651c))\n* **cientos/positional-audio:** fix material issue for the helper, documentation wip ([e0d8f41](https://github.com/Tresjs/cientos/commit/e0d8f41fd6ba32a5b2fdb176eadfc56f251391a2))\n* **cientos/positional-audio:** fix positional async helper and documentation ([f1b9476](https://github.com/Tresjs/cientos/commit/f1b94761ecde13b2e49d6a26fa7a173eeec4f504))\n* **cientos/positional-audio:** improve documentation ([00c4551](https://github.com/Tresjs/cientos/commit/00c4551f367fe05b7a3e3b2888819023244c9c73))\n* **cientos/positional-audio:** improve documentation ([eb30d85](https://github.com/Tresjs/cientos/commit/eb30d8552eeb4b13372c48e96b26237a0d315dc9))\n* **cientos/positional-audio:** improve documentation ([8b65696](https://github.com/Tresjs/cientos/commit/8b656964b6ed8044430075a6a13f51e323a429a6))\n* **cientos/positional-audio:** improve documentation ([a0f02a2](https://github.com/Tresjs/cientos/commit/a0f02a2e8d2c7a96dc1a17099502637e2c557deb))\n* **cientos/positional-audio:** improved code and documentation ([46ca4c4](https://github.com/Tresjs/cientos/commit/46ca4c4f5e6b85671e5d78cb9d59ff21fffd1b1f))\n* **cientos/positional-audio:** rename positionAudioRef ([a036caa](https://github.com/Tresjs/cientos/commit/a036caae705a4fa91642d125355879cb6d517c11))\n* **cientos/positional-audio:** start writing documentation ([1824cbb](https://github.com/Tresjs/cientos/commit/1824cbbacce0242a09f4c405437b4c51a77a1f0f))\n* **cientos/positional-audio:** start writing documentation ([6131e41](https://github.com/Tresjs/cientos/commit/6131e41de1694d8730fa485fbd8a5d3b7d978434))\n* **cientos/transform-controls:** add camera prop ([0ce732d](https://github.com/Tresjs/cientos/commit/0ce732dc4dd74fc5044d7c8b1ad0de18d63a4e86))\n* **docs:** add local prop to docs ([d21694b](https://github.com/Tresjs/cientos/commit/d21694bc5ed6b711c768700b7cfb03145c65ac30))\n* **Fit:** add component, playground, demo ([a521903](https://github.com/Tresjs/cientos/commit/a5219033e79bbb8ec78a49a1277d6adeb699d172))\n\n### Bug Fixes\n* add support for camera prop ([7844743](https://github.com/Tresjs/cientos/commit/78447430076281137bf822d1863ee419d91ca1f7))\n* **app:** 252 Apply review feedback ([4449208](https://github.com/Tresjs/cientos/commit/4449208fccedca0a37ea2e62142b00188a21e0ad))\n* apply feedback ([3a50bc2](https://github.com/Tresjs/cientos/commit/3a50bc29c00dd64775643ab08fe3e5ba569c8248))\n* camera controls ignored props ([37fa163](https://github.com/Tresjs/cientos/commit/37fa163b656a8795727046e363053e99442a46f4))\n* **docs:** better description ([703ab70](https://github.com/Tresjs/cientos/commit/703ab70a69d501d51c448dfdfecc072d83d4b261))\n* little detail in the interface ([fb6456a](https://github.com/Tresjs/cientos/commit/fb6456a063cc28868fe0178b28695c04ad812ccc))\n* transformControls throws error when switching active camera ([f1a477a](https://github.com/Tresjs/cientos/commit/f1a477a46c341f6ed4e58fce1e8999e19feba8d0))\n* **type:** correct the east description ([c26da1f](https://github.com/Tresjs/cientos/commit/c26da1f11524f2445a1b0653f35354de4d3b10ed))\n\n## [4.0.0-next.0](https://github.com/Tresjs/cientos/compare/3.8.0...4.0.0-next.0) (2024-03-27)\n\n\n### Features\n\n* **app:** 252 adding ocean component ([7efb293](https://github.com/Tresjs/cientos/commit/7efb29300a5cda624801316e6bc4f33a88e8de04))\n* **app:** 252 Renamed as ocean, add sky support ([473bac6](https://github.com/Tresjs/cientos/commit/473bac61d9831b9334f4ba78b0d4ab979b7b167f))\n* **app:** Add RoundedBox component ([8b6cb67](https://github.com/Tresjs/cientos/commit/8b6cb67b686bf242aa6e96c3b68af535ddb944d1))\n\n\n### Bug Fixes\n\n* **app:** 252 Apply review feedback ([4449208](https://github.com/Tresjs/cientos/commit/4449208fccedca0a37ea2e62142b00188a21e0ad))\n* apply feedback ([3a50bc2](https://github.com/Tresjs/cientos/commit/3a50bc29c00dd64775643ab08fe3e5ba569c8248))\n* little detail in the interface ([fb6456a](https://github.com/Tresjs/cientos/commit/fb6456a063cc28868fe0178b28695c04ad812ccc))\n\n## [3.8.0](https://github.com/Tresjs/cientos/compare/3.7.0...3.8.0) (2024-02-07)\n\n### Features\n\n* add BakeShadows component ([77df084](https://github.com/Tresjs/cientos/commit/77df0843129bb3957fdd3ea536943fceb046d851))\n* add gltfExporter composable ([0c77d33](https://github.com/Tresjs/cientos/commit/0c77d332240100b31c5a385e2bb1bcd6a21c123c))\n* **app:** 329 Add cast-shadow/receive-shadow to 3D model ([471e28a](https://github.com/Tresjs/cientos/commit/471e28a92ae99097137b6210c32912d04f9c14c4))\n* reflection material ([5cccaa9](https://github.com/Tresjs/cientos/commit/5cccaa9ea3fc42cf6064567430eb1c87dd26a45a))\n\n\n### Bug Fixes\n\n* **app:** 336 Fix stats-gl problem ([505e243](https://github.com/Tresjs/cientos/commit/505e2434fef9f6c9207065fb6ef4af9bdd89fd3a))\n* **deps:** update dependency @tresjs/core to v3.7.0 ([#333](https://github.com/Tresjs/cientos/issues/333)) ([4d09ebb](https://github.com/Tresjs/cientos/commit/4d09ebbcc75c274376dfe6bb179d70bb9e4e861d))\n* reduce beforeRenderer time ([b9df580](https://github.com/Tresjs/cientos/commit/b9df5809fd5543ec6f5140e3899f4867b62f3dc8))\n* reduce lagging on the reflection ([dca5c31](https://github.com/Tresjs/cientos/commit/dca5c31ad0581261e48c6b49bf3022ad3210c216))\n\n\n### Reverts\n\n* remove tweakpane ([#313](https://github.com/Tresjs/cientos/issues/313))\" ([#343](https://github.com/Tresjs/cientos/issues/343)) ([1314abd](https://github.com/Tresjs/cientos/commit/1314abd9b9c0cae0d1bcc202c4b7e9c61d335d5b))\n\n## [3.7.0](https://github.com/Tresjs/cientos/compare/3.6.0...3.7.0) (2023-12-13)\n\n\n### Features\n\n* add 'change' event to pointerlock controls, improve docs ([c394f10](https://github.com/Tresjs/cientos/commit/c394f10b1d219618bfad7619106669fe17c75e32))\n* add rectAreaLightHelper to vLightHelper directive ([#283](https://github.com/Tresjs/cientos/issues/283)) ([8bc64a1](https://github.com/Tresjs/cientos/commit/8bc64a139ee350cb1a3e8d629a6f0c5a44bca973))\n* add reflector ([#136](https://github.com/Tresjs/cientos/issues/136)) ([bd4d710](https://github.com/Tresjs/cientos/commit/bd4d7107bbb990f31ac0feb77feb8729c0b8d019))\n* sampler and useSampler ([#286](https://github.com/Tresjs/cientos/issues/286)) ([826833c](https://github.com/Tresjs/cientos/commit/826833c95d281c76f48d972fc0e7a39ec49ea81a))\n\n\n### Bug Fixes\n\n* remove wrapper element on unmounted ([#310](https://github.com/Tresjs/cientos/issues/310)) ([1a37c92](https://github.com/Tresjs/cientos/commit/1a37c92c8d461f31dfb272089c6299d6305eb1ff))\n* wrap `Text3D` inside `Suspense` in the docs ([#307](https://github.com/Tresjs/cientos/issues/307)) ([27ce1f0](https://github.com/Tresjs/cientos/commit/27ce1f0b54e015c44f1b30cc9b4ffaeb26e06a8a))\n\n## [3.6.0](https://github.com/Tresjs/cientos/compare/3.5.1...3.6.0) (2023-11-07)\n\n\n### Features\n\n* **cientos:** Add `CustomShaderMaterial` wrapper ([#261](https://github.com/Tresjs/cientos/issues/261)) ([43701f8](https://github.com/Tresjs/cientos/commit/43701f824379df4dc7086cdc47a84f91cd18f7de))\n* **Sparkles:** add Sparkles ([#253](https://github.com/Tresjs/cientos/issues/253)) ([cbcc9b9](https://github.com/Tresjs/cientos/commit/cbcc9b9eda16d04da3996954185a57fbb35d7ea4))\n* **Superformula:** add superformula ([#274](https://github.com/Tresjs/cientos/issues/274)) ([19130b4](https://github.com/Tresjs/cientos/commit/19130b429cb20bf562d73275d8def8657241ba64))\n\n\n### Bug Fixes\n\n* avoid html container to be appended again ([#278](https://github.com/Tresjs/cientos/issues/278)) ([8c2b17d](https://github.com/Tresjs/cientos/commit/8c2b17d6965de3ec2d51a9d4aadba857d4d358b5))\n\n\n### Reverts\n\n* **docs:** remove docs/ from .gitignore ([#272](https://github.com/Tresjs/cientos/issues/272)) ([8b5577e](https://github.com/Tresjs/cientos/commit/8b5577eef4b5f0fa0df5ecc7fe4693a31ac96e68))\n\n## [3.5.1](https://github.com/Tresjs/cientos/compare/3.5.0...3.5.1) (2023-10-18)\n\n\n### Bug Fixes\n\n* add key to html slot wrapper to force re-render ([#258](https://github.com/Tresjs/cientos/issues/258)) ([f7a32e2](https://github.com/Tresjs/cientos/commit/f7a32e22954816bc6240fc518f3dbbbd8f8bad96))\n* **OrbitControls:** expose ref ([#250](https://github.com/Tresjs/cientos/issues/250)) ([0f1d162](https://github.com/Tresjs/cientos/commit/0f1d162731292ea338678e74e9a3289c04378412))\n\n## [3.5.0](https://github.com/Tresjs/cientos/compare/3.4.0...3.5.0) (2023-10-10)\n\n\n### Features\n\n* 178 v distance to ([#220](https://github.com/Tresjs/cientos/issues/220)) ([d2e2521](https://github.com/Tresjs/cientos/commit/d2e252108c4913529b92cdbb0fc86f79dbc4337e))\n* 23 html component ([#184](https://github.com/Tresjs/cientos/issues/184)) ([3a488f0](https://github.com/Tresjs/cientos/commit/3a488f0c62f9bab4b2d4b1626f36b4b0d34415e2))\n* add `<Fbo />` abstraction ([#228](https://github.com/Tresjs/cientos/issues/228)) ([6efc076](https://github.com/Tresjs/cientos/commit/6efc07670bbf4b604acae5aa9b3a280c595df733))\n* add global-audio component ([f66d81d](https://github.com/Tresjs/cientos/commit/f66d81d7c9d620ebbe8190ddc78fa99b1defe0f9))\n* change stats to renderless component ([3ae6f5d](https://github.com/Tresjs/cientos/commit/3ae6f5dbf6f824dfb1485f69d476a3c8e43d77c9))\n* **Lines:** add CatumullRomLine, Line2 ([4a267a5](https://github.com/Tresjs/cientos/commit/4a267a5e4661e8f9adc319a7b3a561c34243f3f6))\n* **Lines:** add docs, correct name ([f868d4e](https://github.com/Tresjs/cientos/commit/f868d4e1e7ab738fbe7c846d12e15f1beb49e930))\n* **Lines:** adjust types ([e876314](https://github.com/Tresjs/cientos/commit/e87631436abd2f4bab17ada47dc9a1c70650f38b))\n* **Lines:** correct segments prop description ([a22d25d](https://github.com/Tresjs/cientos/commit/a22d25d582cb5339235056399634116ec754f2eb))\n* **Lines:** fix linter errors ([6ab3ef5](https://github.com/Tresjs/cientos/commit/6ab3ef5ea4e70f10cebc1df6565824e85d6d9bbb))\n* **Lines:** format docs ([a3b612f](https://github.com/Tresjs/cientos/commit/a3b612fc3c94736ba294f9d41960cc27b0ec9350))\n* **Lines:** format docs ([28e78b1](https://github.com/Tresjs/cientos/commit/28e78b137376f9ac25b24ffb2ca6650b7b2ea033))\n* **Lines:** make Line2 import relative ([6788d8e](https://github.com/Tresjs/cientos/commit/6788d8e30045e6b009694bf9769154efafd5e7ec))\n* **Lines:** remove unneeded refs, objects from demos ([128ea59](https://github.com/Tresjs/cientos/commit/128ea59e40ef8ad1e44f8593142a5b9240bd97d6))\n* **Lines:** reword docs ([45002ed](https://github.com/Tresjs/cientos/commit/45002ed0facb2b8586676b690d05a65f5ae2de69))\n* remove pauseTrigger, now play-trigger element also work for pause state when is playing ([6973f23](https://github.com/Tresjs/cientos/commit/6973f23c3e5f0b6193934863a7e53e0449a916ca))\n\n\n### Bug Fixes\n\n* 147 enhance environment and useenvironment abstractions ([#219](https://github.com/Tresjs/cientos/issues/219)) ([876fa9f](https://github.com/Tresjs/cientos/commit/876fa9f01677ba2b0c6d8fa7eac18b08d9dbe884))\n* **deps:** update dependency @tresjs/core to v3.3.0 ([#200](https://github.com/Tresjs/cientos/issues/200)) ([c33d383](https://github.com/Tresjs/cientos/commit/c33d383d08a92643ae60b8e5739305eefd1e4fce))\n* **Levioso:** changing speed causes jerkiness ([#212](https://github.com/Tresjs/cientos/issues/212)) ([a941576](https://github.com/Tresjs/cientos/commit/a941576054ec25c71cb671edc6b6b949bf66a589))\n* v3.4.1 ([#238](https://github.com/Tresjs/cientos/issues/238)) ([8be6c82](https://github.com/Tresjs/cientos/commit/8be6c8276bb89cc054ea0c5781c13146a54e9b2e))\n\n## [3.4.1](https://github.com/Tresjs/cientos/compare/3.4.0...3.4.1) (2023-09-27)\n\n\n### Bug Fixes\n\n* fake commit to force a patch ([b1a055c](https://github.com/Tresjs/cientos/commit/b1a055c07765bb5b97c6b5ff66e2c4183bf54fba))\n* remove es only format bundle ([b9bb1b9](https://github.com/Tresjs/cientos/commit/b9bb1b99905767b4280260e1d439acb7215d0195))\n\n## [3.4.0](https://github.com/Tresjs/cientos/compare/3.3.0...3.4.0) (2023-09-26)\n\n\n### Features\n\n* add first directive vLog ([071c63f](https://github.com/Tresjs/cientos/commit/071c63f5f7723d0cb4722d535bb216edf9d42814))\n* add smoke demo ([6aa3f06](https://github.com/Tresjs/cientos/commit/6aa3f064a99cd64d2149a29c9213393f75252b65))\n* add stats-gl component ([68bee97](https://github.com/Tresjs/cientos/commit/68bee97f5f11292d275d2c3376e8222809d53630))\n* add v-always-look-at directive ([ab3cfa3](https://github.com/Tresjs/cientos/commit/ab3cfa32b791f1188253578119228a52cb28b5a2))\n* add v-light-helper component ([d3e79d7](https://github.com/Tresjs/cientos/commit/d3e79d7dad5075e2bcee5aaa641ace772823f931))\n* **cientos:** 176 remove models ([#199](https://github.com/Tresjs/cientos/issues/199)) ([1314488](https://github.com/Tresjs/cientos/commit/13144884b99de956397f40e436433e598b8bc110))\n* **cientos:** 178 v-light-helper ([#214](https://github.com/Tresjs/cientos/issues/214)) ([0652eed](https://github.com/Tresjs/cientos/commit/0652eed4499e4600a9e1d0ecbb2644b201bb5532))\n* **Lensflare:** add color, distance, size, texture to component ([f90988e](https://github.com/Tresjs/cientos/commit/f90988eae396df7334bfe507e5341bcc1ec4ea08))\n* **Lensflare:** add defaultChoice ([4246245](https://github.com/Tresjs/cientos/commit/4246245c1b06421b51c341a2ef4ca71ffe689c99))\n* **Lensflare:** add docs ([dcd956b](https://github.com/Tresjs/cientos/commit/dcd956b82cc8caa688216b0cb19b22ea65d31b0d))\n* **Lensflare:** add Leches ([14e03a0](https://github.com/Tresjs/cientos/commit/14e03a0548163ce3455d6540f5d424ac7200d095))\n* **Lensflare:** add Lensflare ([6605eaa](https://github.com/Tresjs/cientos/commit/6605eaa1e5081783ed1b9ba2d02f2dd3aa393785))\n* **Lensflare:** add Lensflare ([fb1f52d](https://github.com/Tresjs/cientos/commit/fb1f52d72838d9e9a18cf841e38335232cf9abd7))\n* **Lensflare:** add seed, color ([c895fe1](https://github.com/Tresjs/cientos/commit/c895fe1fadfeaf647bfa3b8b1bc3964098f07f13))\n* **Lensflare:** change exposed ref name ([9279cfe](https://github.com/Tresjs/cientos/commit/9279cfef194ca2ad98f8dc3b14e1e6616c6ea8cd))\n* **Lensflare:** clean up imports ([b8ef198](https://github.com/Tresjs/cientos/commit/b8ef1981c454eb407df9101eae14d78a03eede6b))\n* **Lensflare:** fix linter error ([84f3a79](https://github.com/Tresjs/cientos/commit/84f3a7947abc25b5232ff89434f7cfd6a7418438))\n* **Lensflare:** fix linter errors ([224ecc4](https://github.com/Tresjs/cientos/commit/224ecc4acb44ee0b79eeb50e9ac98b6f3f7cd21a))\n* **Lensflare:** fix path ([7f18278](https://github.com/Tresjs/cientos/commit/7f1827801cf7d5cfcf7f0dbf13bfb46813e33c43))\n* **Lensflare:** fix paths ([7bc7cd2](https://github.com/Tresjs/cientos/commit/7bc7cd2ce31d08528b4ee0b6daf632d85b339101))\n* **Lensflare:** formatting ([fc8ad30](https://github.com/Tresjs/cientos/commit/fc8ad30ea1e7b1fd976d959a52734a02ae064426))\n* **Lensflare:** group constants into objects ([022529f](https://github.com/Tresjs/cientos/commit/022529f1f434c597e4a8759bfe38c8a38a0fe9f7))\n* **Lensflare:** guard against undefined ref value ([2c6c912](https://github.com/Tresjs/cientos/commit/2c6c9123cf92e706a6e15965e68d96d62c43a5aa))\n* **Lensflare:** move easing functions to /src/utils ([f443bbc](https://github.com/Tresjs/cientos/commit/f443bbc51d34e8256a567b3b31490c47d0cc063d))\n* **Lensflare:** move preset values to constants.ts ([9766d6b](https://github.com/Tresjs/cientos/commit/9766d6bc819f683ac32d654b5abedb57fc9ff085))\n* **Lensflare:** move to own subdirectory ([76e897c](https://github.com/Tresjs/cientos/commit/76e897c803f1e1c25a69988ee078dc6208855c63))\n* **Lensflare:** refactor Leches setup ([f8c69c0](https://github.com/Tresjs/cientos/commit/f8c69c05e6c57461144697c27882c4cfde895182))\n* **Lensflare:** refactor Leches setup ([0715ccf](https://github.com/Tresjs/cientos/commit/0715ccfe084ea7286178ff1674007cb34a387f26))\n* **Lensflare:** remove 4, 8 sided textures ([3c23042](https://github.com/Tresjs/cientos/commit/3c2304275c75bcbb8cc89f376be48d104ddfab8e))\n* **Lensflare:** remove duplicate RandUtils ([d816e8e](https://github.com/Tresjs/cientos/commit/d816e8eb82abbf73bbebcc2ce35533d1294ce86e))\n* **Lensflare:** remove scaleRef from demo ([50271ea](https://github.com/Tresjs/cientos/commit/50271ea67256183f1f4d86cb8851ce480be45ad9))\n* **Lensflare:** rename folder ([3fc7374](https://github.com/Tresjs/cientos/commit/3fc7374c953fb52cd397194a09d9206fda2440b8))\n* **Lensflare:** rename function, variables ([e0c382d](https://github.com/Tresjs/cientos/commit/e0c382d052d4e699b9a64ac6e479d8f7e683344b))\n* **Lensflare:** rename prop flare -> elements ([fb199f6](https://github.com/Tresjs/cientos/commit/fb199f6dbbf858d307cdd07aee9c84a29682f7f7))\n* **Lensflare:** resolve infinite while loop bug ([dfa5d8a](https://github.com/Tresjs/cientos/commit/dfa5d8a39095c6d0cf7c3588c3d8e93daebaadc7))\n* **Lensflare:** scale fix ([c439895](https://github.com/Tresjs/cientos/commit/c4398957fe75efe149df829ac4682b85291ddedb))\n* **Lensflare:** simplify prop precedence ([91833e6](https://github.com/Tresjs/cientos/commit/91833e6017c7dbe89f52bf686b6122fe6ed5a1ad))\n* **Lensflare:** smooth out types/conversion ([b9a60e8](https://github.com/Tresjs/cientos/commit/b9a60e808c3c0ce43af34c37cb6bd34f9478988f))\n* **Lensflare:** update route to LensflareDemo ([7dfce1b](https://github.com/Tresjs/cientos/commit/7dfce1b06c557a1421c06db5022bf6d30050e14e))\n* **Lensflare:** update seed with random value ([fba64dc](https://github.com/Tresjs/cientos/commit/fba64dc2720884eb16dcae446de9dd7a066c0ea6))\n* **Lensflare:** use Tresjs/assets for texture URLS ([3dc7e90](https://github.com/Tresjs/cientos/commit/3dc7e9010a6ee75ad50849701dd2d09a576df8d7))\n* **RandUtils:** add RandUtils ([e1693c1](https://github.com/Tresjs/cientos/commit/e1693c11369791b075341533f1e5fd350240b789))\n* **RandUtils:** add RandUtils ([5fa7111](https://github.com/Tresjs/cientos/commit/5fa7111078b683cb15951d1dbb27691e81a8b304))\n* remove cardbobot, suzanne. Add blender-cube in backdrop demo ([c9f95ac](https://github.com/Tresjs/cientos/commit/c9f95acd260470a26ccce8db9bd700b1039924d2))\n* **Sky:** add distance prop to docs ([5c29e9b](https://github.com/Tresjs/cientos/commit/5c29e9b0bb3c058a8649b2ad86476933e7b1b3e0))\n* **Sky:** add distance to demo ([7440216](https://github.com/Tresjs/cientos/commit/74402160cf3045a0c528b851d2609ee82c940c27))\n* **Sky:** add docs ([110e4a8](https://github.com/Tresjs/cientos/commit/110e4a8773fbaf422bbe2be22a6aaed9e3eba23e))\n* **Sky:** add exposure to demo ([323fc82](https://github.com/Tresjs/cientos/commit/323fc829f2ee7a0439fd7f94de689e36b9426da5))\n* **Sky:** add Sky ([894d71e](https://github.com/Tresjs/cientos/commit/894d71ee6eb9e51b9526e4dd281fa86f5aa463d4))\n* **Sky:** change azimuth default ([12b7c38](https://github.com/Tresjs/cientos/commit/12b7c386d59cd09047d4c82693daf2be47fd68ff))\n* **Sky:** disable zoom/pan idiomatically in demo ([08d2f67](https://github.com/Tresjs/cientos/commit/08d2f67095cfa1bb34cff101b4f9ec040e6d98ec))\n* **Sky:** fix linter whitespace errors ([dbc191d](https://github.com/Tresjs/cientos/commit/dbc191d73019d3eb5e1faa040cac5c025d9e6dcf))\n* **Sky:** make prop descriptions consistent in docs ([a62b6d2](https://github.com/Tresjs/cientos/commit/a62b6d2fd7d4050c1218fd63e0986f961ea8ed3a))\n* **Sky:** remove grid ([0eaa3e6](https://github.com/Tresjs/cientos/commit/0eaa3e6c5f2785045eddcf1076aa65e659c26c85))\n* **Sky:** remove unused ref from from demo ([4968785](https://github.com/Tresjs/cientos/commit/496878597b5ecdefc7c014b1a934b0d81dca339b))\n* **Sky:** set demo max mieDirectionalG to 0.99 ([a4475db](https://github.com/Tresjs/cientos/commit/a4475db929acf50c923a0af9d6d670da705b2d0d))\n* **Sky:** use Vue props instead of watchers for uniforms ([c45ed6f](https://github.com/Tresjs/cientos/commit/c45ed6f9e840d5c38bdec60e06aff9852a5dbb18))\n\n\n### Bug Fixes\n\n* check background prop if its empty string ([#217](https://github.com/Tresjs/cientos/issues/217)) ([ec20d69](https://github.com/Tresjs/cientos/commit/ec20d69412bec12ca3fb8cc5b04c4c00e33d22db))\n* use camera's z position as default distance in CameraControls ([8a62a43](https://github.com/Tresjs/cientos/commit/8a62a436e7ca4de50b89665e0e77584feba97578))\n\n## [3.3.0](https://github.com/Tresjs/cientos/compare/3.2.1...3.3.0) (2023-09-11)\n\n\n### Features\n\n* 158 stats ([#166](https://github.com/Tresjs/cientos/issues/166)) ([4a71885](https://github.com/Tresjs/cientos/commit/4a71885dc585a6a8ee733239fe73453157eca85c))\n* add distance prop in camera controls ([388b5de](https://github.com/Tresjs/cientos/commit/388b5de4a7819fe9ef4c09ff9828a102661893dd))\n* SVG ([28e3b6a](https://github.com/Tresjs/cientos/commit/28e3b6a4a47bfe2db16ed61214ea6d4cbddcb0c3))\n* **SVG:** add depth demo ([ba1fd18](https://github.com/Tresjs/cientos/commit/ba1fd18ff18d52b4eec4d93d70ffd19c058055a6))\n* **SVG:** add depth options ([e453a1d](https://github.com/Tresjs/cientos/commit/e453a1dad3a67a7bf612294a016a7c2cced851c7))\n* **SVG:** add docs ([b176dc4](https://github.com/Tresjs/cientos/commit/b176dc4fb782b151ba2f2acb9b3b1434db897ba2))\n* **SVG:** change 'depth' default to 'renderOrder' ([5c1dd27](https://github.com/Tresjs/cientos/commit/5c1dd2731c2974b5e3aaaa088393f25c3edb742a))\n* **SVG:** dispose of geometries ([a75d571](https://github.com/Tresjs/cientos/commit/a75d57189697405dbe2ebc6a67746fd2de4065f2))\n* **SVG:** fix linter warnings ([80dbaab](https://github.com/Tresjs/cientos/commit/80dbaabdbd27daa4145dbbd9bb75635c8ac9f0bf))\n* **SVG:** fix type error ([4439aa1](https://github.com/Tresjs/cientos/commit/4439aa10bdc8ef4e3b3d7a353a627fcf40cedf82))\n* **SVG:** remove depth prop demo ([ca82737](https://github.com/Tresjs/cientos/commit/ca82737f3a82de6a7bfbb56ae708b694ac6fa873))\n* **SVG:** remove depth prop from demo ([87ceb34](https://github.com/Tresjs/cientos/commit/87ceb34a368680119843287ac824ca43d51f0bd8))\n* **SVG:** remove key ([01061a9](https://github.com/Tresjs/cientos/commit/01061a9b3e9ffc356ee20c1948c10197aa3f085e))\n* **SVG:** remove unused variable ([c85a96f](https://github.com/Tresjs/cientos/commit/c85a96fa227ec71d063365f18f1820a4679d9fee))\n* **SVG:** rename exposed ref ([95bada9](https://github.com/Tresjs/cientos/commit/95bada9d80893fcd0c29cbc300b6ca82c366831d))\n* **SVG:** split line for linter ([469273a](https://github.com/Tresjs/cientos/commit/469273acbe61ecc5b3aee611f5b0cc0945b99b1b))\n* **SVG:** update JSDoc ([8c0aaf6](https://github.com/Tresjs/cientos/commit/8c0aaf6dc87396b3ac07bc251e78bfdc64a6d548))\n* **SVG:** update props, depth in docs ([da85374](https://github.com/Tresjs/cientos/commit/da853745a0c3949f5c3f08c92f360206ee688763))\n* **SVG:** whitespace ([d83493b](https://github.com/Tresjs/cientos/commit/d83493b76f0e37910ebdd012483649ef39e23c39))\n* update lint rules, ([#196](https://github.com/Tresjs/cientos/issues/196)) ([ccdf81f](https://github.com/Tresjs/cientos/commit/ccdf81f89805e7b4d546592e2a188d704449439e))\n\n\n### Bug Fixes\n\n* **cientos:** controls props priority ([a9e47fc](https://github.com/Tresjs/cientos/commit/a9e47fc17c5507d1f0c37cfa05c9e7c1d57b4d95))\n* dead link ([f784021](https://github.com/Tresjs/cientos/commit/f784021d949bac5cac8dad90e572ea7794c6bb29))\n* set `@tresjs/core` as peer ([#211](https://github.com/Tresjs/cientos/issues/211)) ([9636ec9](https://github.com/Tresjs/cientos/commit/9636ec976fa2414f78f69f7e970dd50a7222c384))\n\n## [3.3.0-next.0](https://github.com/Tresjs/cientos/compare/3.2.1...3.3.0-next.0) (2023-09-11)\n\n\n### Features\n\n* 158 stats ([#166](https://github.com/Tresjs/cientos/issues/166)) ([4a71885](https://github.com/Tresjs/cientos/commit/4a71885dc585a6a8ee733239fe73453157eca85c))\n* add distance prop in camera controls ([388b5de](https://github.com/Tresjs/cientos/commit/388b5de4a7819fe9ef4c09ff9828a102661893dd))\n* SVG ([28e3b6a](https://github.com/Tresjs/cientos/commit/28e3b6a4a47bfe2db16ed61214ea6d4cbddcb0c3))\n* **SVG:** add depth demo ([ba1fd18](https://github.com/Tresjs/cientos/commit/ba1fd18ff18d52b4eec4d93d70ffd19c058055a6))\n* **SVG:** add depth options ([e453a1d](https://github.com/Tresjs/cientos/commit/e453a1dad3a67a7bf612294a016a7c2cced851c7))\n* **SVG:** add docs ([b176dc4](https://github.com/Tresjs/cientos/commit/b176dc4fb782b151ba2f2acb9b3b1434db897ba2))\n* **SVG:** change 'depth' default to 'renderOrder' ([5c1dd27](https://github.com/Tresjs/cientos/commit/5c1dd2731c2974b5e3aaaa088393f25c3edb742a))\n* **SVG:** dispose of geometries ([a75d571](https://github.com/Tresjs/cientos/commit/a75d57189697405dbe2ebc6a67746fd2de4065f2))\n* **SVG:** fix linter warnings ([80dbaab](https://github.com/Tresjs/cientos/commit/80dbaabdbd27daa4145dbbd9bb75635c8ac9f0bf))\n* **SVG:** fix type error ([4439aa1](https://github.com/Tresjs/cientos/commit/4439aa10bdc8ef4e3b3d7a353a627fcf40cedf82))\n* **SVG:** remove depth prop demo ([ca82737](https://github.com/Tresjs/cientos/commit/ca82737f3a82de6a7bfbb56ae708b694ac6fa873))\n* **SVG:** remove depth prop from demo ([87ceb34](https://github.com/Tresjs/cientos/commit/87ceb34a368680119843287ac824ca43d51f0bd8))\n* **SVG:** remove key ([01061a9](https://github.com/Tresjs/cientos/commit/01061a9b3e9ffc356ee20c1948c10197aa3f085e))\n* **SVG:** remove unused variable ([c85a96f](https://github.com/Tresjs/cientos/commit/c85a96fa227ec71d063365f18f1820a4679d9fee))\n* **SVG:** rename exposed ref ([95bada9](https://github.com/Tresjs/cientos/commit/95bada9d80893fcd0c29cbc300b6ca82c366831d))\n* **SVG:** split line for linter ([469273a](https://github.com/Tresjs/cientos/commit/469273acbe61ecc5b3aee611f5b0cc0945b99b1b))\n* **SVG:** update JSDoc ([8c0aaf6](https://github.com/Tresjs/cientos/commit/8c0aaf6dc87396b3ac07bc251e78bfdc64a6d548))\n* **SVG:** update props, depth in docs ([da85374](https://github.com/Tresjs/cientos/commit/da853745a0c3949f5c3f08c92f360206ee688763))\n* **SVG:** whitespace ([d83493b](https://github.com/Tresjs/cientos/commit/d83493b76f0e37910ebdd012483649ef39e23c39))\n* update lint rules, ([#196](https://github.com/Tresjs/cientos/issues/196)) ([ccdf81f](https://github.com/Tresjs/cientos/commit/ccdf81f89805e7b4d546592e2a188d704449439e))\n\n\n### Bug Fixes\n\n* **cientos:** controls props priority ([a9e47fc](https://github.com/Tresjs/cientos/commit/a9e47fc17c5507d1f0c37cfa05c9e7c1d57b4d95))\n* dead link ([f784021](https://github.com/Tresjs/cientos/commit/f784021d949bac5cac8dad90e572ea7794c6bb29))\n* set `@tresjs/core` as peer ([77f7a3c](https://github.com/Tresjs/cientos/commit/77f7a3ca39dd1c433db5e64afa73076943baea15))\n\n## [3.2.1](https://github.com/Tresjs/cientos/compare/3.2.0...3.2.1) (2023-09-01)\n\n\n### Bug Fixes\n\n* **deps:** update dependency @tresjs/core to v3.1.1 ([#186](https://github.com/Tresjs/cientos/issues/186)) ([0f5d9cf](https://github.com/Tresjs/cientos/commit/0f5d9cf2b4b00f9762a1de6df617b6b63cda7f75))\n* removed `toFixed` for progress value ([#191](https://github.com/Tresjs/cientos/issues/191)) ([d46f90f](https://github.com/Tresjs/cientos/commit/d46f90f6e11c66f2fdf570340d91f63996bc94b1))\n\n## [3.2.0](https://github.com/Tresjs/cientos/compare/3.1.0...3.2.0) (2023-08-25)\n\n\n### Features\n\n* 107 use video texture ([#167](https://github.com/Tresjs/cientos/issues/167)) ([f0f1f9b](https://github.com/Tresjs/cientos/commit/f0f1f9bc6107c2d040195ca76f647ef6dcbeb2d3))\n* add glass material ([#172](https://github.com/Tresjs/cientos/issues/172)) ([5f60864](https://github.com/Tresjs/cientos/commit/5f608640ccd4eaa14357101a3784eeeac3592646))\n\n\n### Bug Fixes\n\n* 179 tweakpane plugin essentials ([#180](https://github.com/Tresjs/cientos/issues/180)) ([67b8d57](https://github.com/Tresjs/cientos/commit/67b8d57bbfdbdcd01e7a24f470934acafa6ae300))\n\n## [3.2.0-next.0](https://github.com/Tresjs/cientos/compare/3.1.0...3.2.0-next.0) (2023-08-23)\n\n\n### Features\n\n* 107 use video texture ([#167](https://github.com/Tresjs/cientos/issues/167)) ([f0f1f9b](https://github.com/Tresjs/cientos/commit/f0f1f9bc6107c2d040195ca76f647ef6dcbeb2d3))\n\n\n### Bug Fixes\n\n* remove tweakpane essentials import ([eeed334](https://github.com/Tresjs/cientos/commit/eeed334398374089d17b3ebf34bfc7b5f963372b))\n\n## [3.1.0](https://github.com/Tresjs/cientos/compare/3.0.1...3.1.0) (2023-08-17)\n\n\n### Features\n\n* add camera controls to new context ([21ab955](https://github.com/Tresjs/cientos/commit/21ab955b9e8560d513a1804387e6bac707245a38))\n* chg to event, rmv vmodel, ([9b739a2](https://github.com/Tresjs/cientos/commit/9b739a23ef860ba8f3fe8120beaba76fc794fade))\n* remove tweakpane deps from final bundle ([#169](https://github.com/Tresjs/cientos/issues/169)) ([b99ac3c](https://github.com/Tresjs/cientos/commit/b99ac3cdc957d3fb1cd8257d03cde316ab22b573))\n\n\n### Bug Fixes\n\n* useGLTF return types ([#174](https://github.com/Tresjs/cientos/issues/174)) ([7f78106](https://github.com/Tresjs/cientos/commit/7f781069ca7d04986790ff644e8b3c8b62446a20))\n\n## [3.0.1](https://github.com/Tresjs/cientos/compare/3.0.0...3.0.1) (2023-07-29)\n\n\n### Bug Fixes\n\n* removed axesHelper from Contact Shadows ([#152](https://github.com/Tresjs/cientos/issues/152)) ([821205a](https://github.com/Tresjs/cientos/commit/821205ad3780a28b18554de9f1f544c884287181))\n\n## [3.0.0](https://github.com/Tresjs/cientos/compare/2.3.0...3.0.0) (2023-07-29)\n\n\n### ⚠ BREAKING CHANGES\n\n* core v3 provides a new state context `useTresContext` which impacts all the abstractions depending on the state\n\n* chore: move core to deps\n\n* chore: updated lock\n\n* chore: fix lint\n\n* feat: removed useCientos and useTresContext instead\n\n### Features\n\n* 120 refactor usecientos to new state context provider ([#143](https://github.com/Tresjs/cientos/issues/143)) ([723a323](https://github.com/Tresjs/cientos/commit/723a3231da239a1214d0ffdfb3b6a6e7cb62eedc))\n* add more camera-controls playground examples ([d3c5dd3](https://github.com/Tresjs/cientos/commit/d3c5dd3ceefe3d816abd268f4b1a994d024f0d37))\n* add preliminary camera-controls abstraction ([bef41b9](https://github.com/Tresjs/cientos/commit/bef41b9f0ef6508ecd56735cd5e2d6fb205e114a))\n* backdrop stage abstraction ([#116](https://github.com/Tresjs/cientos/issues/116)) ([62f677c](https://github.com/Tresjs/cientos/commit/62f677c881dfc7b0386a79f9d5b0c162596c2838))\n\n\n### Bug Fixes\n\n* add reactivity to stars component, rmv factor as props unnecessary ([#144](https://github.com/Tresjs/cientos/issues/144)) ([ad5c6c8](https://github.com/Tresjs/cientos/commit/ad5c6c8572f2ac472063886fde48c63f81b667dc))\n* background not checked right useEnvironment ([#138](https://github.com/Tresjs/cientos/issues/138)) ([28d40fd](https://github.com/Tresjs/cientos/commit/28d40fde9a690cb44943c875799e48f3c17d5eb4))\n* map correct camera-controls events ([e7095eb](https://github.com/Tresjs/cientos/commit/e7095ebe958e690de0a8aba37a55679f6a321e10))\n* MouseParallax, clean code ([#134](https://github.com/Tresjs/cientos/issues/134)) ([257238a](https://github.com/Tresjs/cientos/commit/257238aa38bc921983dc4ae37ac4891becfb5113))\n* nuxt problem with scrollControls ([#130](https://github.com/Tresjs/cientos/issues/130)) ([1739965](https://github.com/Tresjs/cientos/commit/1739965dbbd3e7aef9921a91c6ffbfe5502074aa))\n\n## [2.3.0](https://github.com/Tresjs/cientos/compare/2.2.0...2.3.0) (2023-07-11)\n\n\n### Features\n\n* scroll-controls ([#118](https://github.com/Tresjs/cientos/issues/118)) ([293fcdc](https://github.com/Tresjs/cientos/commit/293fcdc2365c27a3565626d148d465ed52d0ef55))\n\n\n### Bug Fixes\n\n* initial camera position in keyboard controls ([#119](https://github.com/Tresjs/cientos/issues/119)) ([e4a03a6](https://github.com/Tresjs/cientos/commit/e4a03a6d7484c0c626142e79f3cc4dd9a43fdb25))\n* remove deconstructive props ([#124](https://github.com/Tresjs/cientos/issues/124)) ([d83d00d](https://github.com/Tresjs/cientos/commit/d83d00d089467807fd1f5bdb42a4df761dc44237))\n\n## [2.2.0](https://github.com/Tresjs/cientos/compare/2.1.4...2.2.0) (2023-06-29)\n\n\n### Features\n\n* keyboard controls ([#68](https://github.com/Tresjs/cientos/issues/68)) ([1b7a624](https://github.com/Tresjs/cientos/commit/1b7a624159db5370c89c9f0fd1f99ed3c6cc6d8a))\n* useProgress composable ([b6f3f33](https://github.com/Tresjs/cientos/commit/b6f3f333caa31234a10c89ad0b5edb61410c2a47))\n\n\n### Bug Fixes\n\n* add playground to examples ([#104](https://github.com/Tresjs/cientos/issues/104)) ([ce442a4](https://github.com/Tresjs/cientos/commit/ce442a44e44d69142f6a0d57c16692a84cf8c915))\n* added default for touches prop ([#100](https://github.com/Tresjs/cientos/issues/100)) ([#111](https://github.com/Tresjs/cientos/issues/111)) ([de6ebab](https://github.com/Tresjs/cientos/commit/de6ebab31c833f0ed4676e531a17572c46478177))\n* **deps:** update dependency @tresjs/core to v2.3.0 ([599f36b](https://github.com/Tresjs/cientos/commit/599f36b0df72a315f45aa485a78256cfce75c329))\n* styles in dark theme, same as in the core ([#105](https://github.com/Tresjs/cientos/issues/105)) ([1a8d0a5](https://github.com/Tresjs/cientos/commit/1a8d0a5b4cb083581c9adfd5dc687f79befc6f8b))\n* useProgress correct export from loaders ([af33533](https://github.com/Tresjs/cientos/commit/af335337569eaa5bb33bbc91298dd5482e354423))\n\n### [2.1.4](https://github.com/Tresjs/cientos/compare/2.1.2...2.1.4) (2023-06-14)\n\n\n### Bug Fixes\n\n* chg log linter rule to warn ([18eeb72](https://github.com/Tresjs/cientos/commit/18eeb72771339ad0c7e6c5d41ceb47caf392ca28))\n* fix types in precipitation, stars. rmv log rule linter ([1c15ecb](https://github.com/Tresjs/cientos/commit/1c15ecbe12250d5c1f2f3ef0a347eb8947c77413))\n* precipitation-area issue, rmv log mouseparallax, add rule lint ([994efaa](https://github.com/Tresjs/cientos/commit/994efaa3785d3ab02e27f31a2485c37d9f82727f))\n* return control value on event emitters ([d072223](https://github.com/Tresjs/cientos/commit/d072223afd055c5e00fa7f608c0a2f1a850b699f))\n\n### [2.1.2](https://github.com/Tresjs/cientos/compare/2.1.1...2.1.2) (2023-05-26)\n\n\n### Bug Fixes\n\n* fix lint on the demo ([8873e41](https://github.com/Tresjs/cientos/commit/8873e411cbe742532f1a88157f5d41f59253b220))\n* refactor transform controls with deconstructor ([8e7f673](https://github.com/Tresjs/cientos/commit/8e7f673f20016148749f3b14af0940a303d27b38))\n\n### [2.1.1](https://github.com/Tresjs/cientos/compare/2.1.0...2.1.1) (2023-05-24)\n\n\n### Bug Fixes\n\n* contact shadows helper as prop ([f7054d0](https://github.com/Tresjs/cientos/commit/f7054d0d471ad3636841ee625801eaf5950a1225))\n\n## [2.1.0](https://github.com/Tresjs/cientos/compare/2.0.0...2.1.0) (2023-05-24)\n\n\n### Features\n\n* add events to orbit controls ([6815d12](https://github.com/Tresjs/cientos/commit/6815d126731005d777bb451ba478009407388f5f))\n* add Rain component ([7dca86d](https://github.com/Tresjs/cientos/commit/7dca86d11e796fa04da51a9a415fa971880379e6))\n* contact shadows is alive and reactive ([188cf8c](https://github.com/Tresjs/cientos/commit/188cf8c4431c857bd8d9c562b36c4dd5816af25e))\n* contact-shadows implementation ([81baf86](https://github.com/Tresjs/cientos/commit/81baf8618de9d8dc1e25d0fc9c40671f4255ffbf))\n* deconstruct those Props ([ccd0581](https://github.com/Tresjs/cientos/commit/ccd058170b9c83032f616046d36df030df4bb001))\n* enhanced orbit-controls ([27f2e88](https://github.com/Tresjs/cientos/commit/27f2e886e8f39a308ce5cc12c9025c155c560b22))\n* temporally tweak eslint for deconstructed props ([8803e8f](https://github.com/Tresjs/cientos/commit/8803e8faa74d8dfa5d6df0af661a9d7359c2a913))\n* update parallax mouse abstraction ([88885a3](https://github.com/Tresjs/cientos/commit/88885a3a815dfc1b13b2eb7cbec136078f81d48c))\n* update to core v2.1.0 and fix types ([f099387](https://github.com/Tresjs/cientos/commit/f099387ff16511632b0fcfc6afac3f774f25f144))\n\n\n### Bug Fixes\n\n* added missing prop target and removed withDefaults ([43ddf6b](https://github.com/Tresjs/cientos/commit/43ddf6b7c4028fc0184f153070d67f2adee76fb8))\n* change smoke texture encoding for colorSpace ([2338803](https://github.com/Tresjs/cientos/commit/23388035bb7b94f3321c1850c5410f59d8ba4d27))\n* core types ([266088b](https://github.com/Tresjs/cientos/commit/266088b2a8e29d06e6dbdcc3b4fe40b12b8c8397))\n* event headline h2 ([c506769](https://github.com/Tresjs/cientos/commit/c50676956fd98a6b5750a63c0cbbda8b658ba8e3))\n* remove import leftovers ([fef7e86](https://github.com/Tresjs/cientos/commit/fef7e861647314845f619213c53608e9e8d505d4))\n* templateRef  name casing ([8844612](https://github.com/Tresjs/cientos/commit/8844612e804f87536963d82302ba0858fad48b2b))\n\n## [2.0.0](https://github.com/Tresjs/cientos/compare/2.0.0-rc.3...2.0.0) (2023-05-12)\n\n## [2.0.0-rc.3](https://github.com/Tresjs/cientos/compare/2.0.0-rc.1...2.0.0-rc.3) (2023-05-08)\n\n\n### Bug Fixes\n\n* fbxModel inherit props ([b15935e](https://github.com/Tresjs/cientos/commit/b15935e6a9d680b7e7159f8057493b7c1befb62f))\n* gltfModel inherit props ([a80506e](https://github.com/Tresjs/cientos/commit/a80506e6ce41e98df588e31b0e3f8d08e130cb01))\n\n## [2.0.0-rc.1](https://github.com/Tresjs/cientos/compare/2.0.0-rc.0...2.0.0-rc.1) (2023-05-03)\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to make participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.\n\n## Our Standards\n\nExamples of behavior that contributes to creating a positive environment include:\n\n- Using welcoming and inclusive language\n- Being respectful of differing viewpoints and experiences\n- Gracefully accepting constructive criticism\n- Focusing on what is best for the community\n- Showing empathy towards other community members\n\nExamples of unacceptable behavior by participants include:\n\n- The use of sexualized language or imagery and unwelcome sexual attention or advances\n- Trolling, insulting/derogatory comments, and personal or political attacks\n- Public or private harassment\n- Publishing others’ private information, such as a physical or electronic address, without explicit permission\n- Other conduct which could reasonably be considered inappropriate in a professional setting\n\n## Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.\n\n## Scope\n\nThis Code of Conduct applies within all project spaces, and it also applies when an individual is representing the project or its community in public spaces. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team by DM at [TresJS Discord](https://discord.gg/UCr96AQmWn). All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project’s leadership.\n\n## Attribution\n\nThis Code of Conduct is adapted from the Contributor Covenant, version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "![repository-banner.png](https://res.cloudinary.com/alvarosaburido/image/upload/v1683452574/repo-banner_d2xeem.png)\n\n# Tres Contributing Guide\n\nHi there!! If you are reading this guide, you are probably interested in contributing to Tres. You're awesome 🤩.\n\nNo contribution is too small, whether it is a typo in the docs, a bug report or refactoring a piece of code, every contribution is welcome, just make sure to follow the guidelines below ✌️.\n\nThanks from the heart 💚 for taking the time to help out. This guide will help you to get started with the project.\n\n## Ecosystem\n- [@tresjs/core](https://github.com/Tresjs/tres) - The core package.\n- [@tresjs/cientos](https://github.com/Tresjs/cientos) - The abstractions package.\n- [@tresjs/postprocessing](https://github.com/Tresjs/post-processing) - The post-processing package.\n\n## Setup\n\nAll the packages in the ecosystem use [pnpm workspaces](https://pnpm.io/workspaces). PnPM is a package manager that is faster than npm and yarn. It also uses symlinks to avoid code duplication.\n\nThe `workspace` has the following structure:\n\n```\n.\n├── docs // The documentation\n├── playground // The playground to test the package\n├── src // The source code\n\n```\n\nMake sure you are using [Node.js](https://nodejs.org/en/) version 14 or higher.\n\nYou can install pnpm using npm:\n\n```bash\nnpm install -g pnpm\n```\n\nor using homebrew:\n\nIf you have the package manager installed, you can install pnpm using the following command:\n\n```\nbrew install pnpm\n```\n\n## Development\n\nTo start developing, you can run `pnpm playground` in the root folder.\n\nThis will start the dev server for the playground at `http://localhost:5173/` where you can test the changes you are making in the `src` folder.\n\n> **Important**\n> There is no need to run anything in the `src` folder or in the root, the `playground` will take care of it\n\nWhenever you are working on a new feature or fixing a bug, make sure to add a demo under `playground/src/pages` and create a route in the `playground/src/router.ts` to test the changes you are making.\n\n> **Warning**\n> Make sure to check if there is already a demo for the feature you are working on. If so, feel free to add your changes to the existing demo.\n\n### Docs\n\nThe docs are built using [vitepress](https://vitepress.vuejs.org/).\n\nYou can run `pnpm docs:dev` to start the dev server for the documentation. All the docs are located in the `docs` folder in markdown.\n\nIf you are adding a new page, make sure to add it to the `docs/.vitepress/config.ts` file following the sidebar structure.\n\n### Testing\n\nCurrently there are no tests in place, but we are working on it. If you want to contribute with tests, please open an issue first to discuss the best approach.\n\n## Pull Requests\n\nBefore opening a pull request, make sure to run `pnpm lint` to make sure the code is following the code style.\n\n- Checkout a topic branch from the base branch `main` branch and merge back against that branch.\n- Please follow the [commit message conventions](https://www.conventionalcommits.org/en/v1.0.0-beta.4/) when committing your changes. This is important because the release notes will be automatically generated from these messages. Small scoped commits are always preferred, as it is easier to review them.\n- If adding new feature:\n  - Provide convincing reason to add this feature. Ideally you should open a suggestion issue first and have it greenlighted before working on it. We would reject feature PRs that are not first opened as suggestions except for trivial changes.\n  - Create a `feature/{issue-number}-add-test-to-cientos` branch for this feature. Make the name meaningful.\n  - PR title must start with `feat(pkg): Descriptive title`. For example: `feat(cientos): added unit test to composables`.\n- If fixing a bug 🐛:\n\n  - Provide detailed description of the bug in the PR. Live demo preferred.\n  - Create a `fix/{issue-number}-fix-test-in-core` branch for this bug fix.\n  - If you are resolving a special issue, add `(fix #xxx[,#xxx])` (#xxx is the issue id) in your PR title for a better release log, e.g. `update entities encoding/decoding (fix #3899)`.\n\n## Third Party Libraries\n\nAdding a new third party library is generally discouraged, unless it is absolutely necessary. If you want to add a new library, please open an issue first to discuss the best approach.\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2022-present, (alvarosabu) Alvaro Saburido and Tres contributors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# ⚠️ This repository has been archived\n\nThis package has been moved to the TresJS monorepo.\n\n## New Location\n\n👉 **[github.com/Tresjs/tres](https://github.com/Tresjs/tres)**\n\nAll future development, issues, and pull requests should be directed to the monorepo.\n\n## Installation\n\nThe package is still available on npm with the same name. Installation instructions remain the same:\n\n```bash\npnpm add @tresjs/cientos\n```\n\n## Documentation\n\n📚 Visit [docs.tresjs.org](https://docs.tresjs.org) for the latest documentation.\n"
  },
  {
    "path": "core.d.ts",
    "content": "export * from './dist/core/index.js'\n"
  },
  {
    "path": "docs/.eslintrc.json",
    "content": "{\n  \"extends\": \"@tresjs/eslint-config-vue\"\n}\n"
  },
  {
    "path": "docs/.vitepress/config.ts",
    "content": "import { defineConfig } from 'vitepress'\nimport { resolve } from 'pathe'\n\nimport components from '../component-list/components'\n\nconst whitelist = ['TresCanvas', 'TresLeches', 'TresScene']\n\n// https://vitepress.dev/reference/site-config\nexport default defineConfig({\n  title: 'Cientos',\n  description:\n    'Collection of useful helpers and fully functional, ready-made abstractions for TresJS',\n  head: [\n    ['link', { rel: 'icon', type: 'image/svg', href: '/favicon.svg' }],\n    ['meta', { name: 'theme-color', content: '#82DBC5' }],\n    ['meta', { name: 'twitter:card', content: 'summary_large_image' }],\n    ['meta', { name: 'twitter:site', content: '@tresjs_dev' }],\n    ['meta', { name: 'twitter:creator', content: '@tresjs_dev' }],\n    ['meta', { property: 'og:type', content: 'website' }],\n    ['meta', { property: 'og:site_name', content: 'Cientos - TresJS' }],\n    [\n      'meta',\n      {\n        property: 'og:image',\n        content:\n          'https://repository-images.githubusercontent.com/571314349/10996566-7f70-473b-a8e5-4e56fc0ca850',\n      },\n    ],\n    [\n      'meta',\n      {\n        property: 'twitter:image',\n        content:\n          'https://repository-images.githubusercontent.com/571314349/10996566-7f70-473b-a8e5-4e56fc0ca850',\n      },\n    ],\n    [\n      'script',\n      {\n        'defer': 'true',\n        'data-site': 'OWBUVCJK',\n        'src': 'https://cdn.usefathom.com/script.js',\n      },\n    ],\n  ],\n  themeConfig: {\n    logo: '/logo.svg',\n    search: {\n      provider: 'local',\n    },\n    // https://vitepress.dev/reference/default-theme-config\n    nav: [\n      { text: 'Guide', link: '/guide/' },\n      { text: 'Components', link: '/component-list/' },\n      { text: 'Examples', link: 'https://lab.tresjs.org/' },\n    ],\n\n    sidebar: [\n      {\n        text: 'Guide',\n        items: [\n          { text: 'Introduction', link: '/guide/' },\n          { text: 'Migration from v3', link: '/guide/migrating-from-v3' },\n        ],\n      },\n      ...components,\n\n    ],\n\n    socialLinks: [\n      { icon: 'github', link: 'https://github.com/tresjs/cientos' },\n      { icon: 'twitter', link: 'https://twitter.com/tresjs_dev' },\n      { icon: 'discord', link: 'https://discord.gg/UCr96AQmWn' },\n    ],\n  },\n  vite: {\n    optimizeDeps: {\n      exclude: ['vitepress'],\n      include: ['three'],\n    },\n    server: {\n      hmr: {\n        overlay: false,\n      },\n    },\n    resolve: {\n      alias: {\n        '@tresjs/cientos': resolve(__dirname, '../../dist/trescientos.js'),\n      },\n      dedupe: ['three'],\n    },\n  },\n  vue: {\n    template: {\n      compilerOptions: {\n        isCustomElement: (tag: string) =>\n          (tag.startsWith('Tres') && !whitelist.includes(tag))\n          || tag === 'primitive',\n      },\n    },\n  },\n})\n"
  },
  {
    "path": "docs/.vitepress/theme/TresLayout.vue",
    "content": "<script setup>\nimport Theme from 'vitepress/theme'\nimport LoveVueThreeJS from './components/LoveVueThreeJS.vue'\n\nconst { Layout } = Theme\n</script>\n\n<template>\n  <Layout>\n    <template #home-hero-image>\n      <LoveVueThreeJS />\n    </template>\n  </Layout>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/AccumulativeShadowsDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { AccumulativeShadows, OrbitControls } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\n</script>\n\n<template>\n  <TresCanvas clear-color=\"#fbb03b\" :shadows=\"true\">\n    <OrbitControls />\n    <TresMesh :position-y=\"0.3\" :scale=\"0.4\" :cast-shadow=\"true\">\n      <TresTorusKnotGeometry />\n      <TresMeshNormalMaterial />\n    </TresMesh>\n    <AccumulativeShadows\n      :blend=\"100\"\n      color=\"#fbb03b\"\n      once\n      :position-y=\"-0.4\"\n    />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/AlignDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { Align, OrbitControls } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\n</script>\n\n<template>\n  <TresCanvas clear-color=\"#222\">\n    <TresPerspectiveCamera />\n    <OrbitControls />\n\n    <TresAxesHelper :scale=\"2\" />\n\n    <Align top right back>\n      <TresMesh>\n        <TresBoxGeometry />\n        <TresMeshNormalMaterial />\n      </TresMesh>\n    </Align>\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/AnimatedSpriteCenterDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { AnimatedSprite, Box, OrbitControls } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { TresLeches, useControls } from '@tresjs/leches'\nimport type { AtlasData } from '../../../../src/core/abstractions/AnimatedSprite/Atlas'\nimport '@tresjs/leches/styles'\n\nconst { centerX, centerY, fps, asSprite } = useControls({\n  centerX: { value: 0.5, min: 0, max: 1, step: 0.1 },\n  centerY: { value: 0.5, min: 0, max: 1, step: 0.1 },\n  fps: { value: 5, min: 0, max: 30, step: 1 },\n  asSprite: true,\n})\n\nconst centerDemoAtlas: AtlasData = { frames: [] }\nconst centerDemoImgData = (() => {\n  const NUM_ROWS_COLS = 64\n  const rects: { x: number, y: number, w: number, h: number }[] = []\n  let h = 0\n  for (let r = 0; r < NUM_ROWS_COLS; r += h) {\n    let w = 0\n    h++\n    if (r + h >= NUM_ROWS_COLS) {\n      continue\n    }\n    for (let c = 0; c < NUM_ROWS_COLS; c += w) {\n      w++\n      if (c + w >= NUM_ROWS_COLS) {\n        continue\n      }\n      rects.push({ x: c, y: r, w, h })\n    }\n  }\n\n  const canvas = document.createElement('canvas')\n  const IMG_SIZE = 2048\n  const COL_SIZE = IMG_SIZE / NUM_ROWS_COLS\n  const ROW_SIZE = IMG_SIZE / NUM_ROWS_COLS\n  canvas.width = IMG_SIZE\n  canvas.height = IMG_SIZE\n  document.body.append(canvas)\n  const ctx = canvas.getContext('2d')!\n  const EDGE_center_SIZE = 6\n  rects.forEach((rect, i) => {\n    const frame = { x: rect.x * COL_SIZE, y: rect.y * ROW_SIZE, w: rect.w * COL_SIZE, h: rect.h * ROW_SIZE }\n    const { x, y, w, h } = frame\n    centerDemoAtlas.frames.push({ filename: `rect_${i.toString().padStart(4, '0')}`, frame })\n    ctx.fillStyle = '#222'\n    ctx.fillRect(x, y, w, h)\n\n    ctx.fillStyle = '#999'\n    ctx.fillRect(\n      x + w * 0.5 - EDGE_center_SIZE * 0.5,\n      y + h * 0.5 - EDGE_center_SIZE * 0.5,\n      EDGE_center_SIZE,\n      EDGE_center_SIZE,\n    )\n\n    ctx.fillRect(x, y, EDGE_center_SIZE, EDGE_center_SIZE)\n    ctx.fillRect(x + w * 0.5 - EDGE_center_SIZE * 0.5, y, EDGE_center_SIZE, EDGE_center_SIZE)\n    ctx.fillRect(x + w - EDGE_center_SIZE, y, EDGE_center_SIZE, EDGE_center_SIZE)\n\n    ctx.fillRect(x, y + h * 0.5 - EDGE_center_SIZE * 0.5, EDGE_center_SIZE, EDGE_center_SIZE)\n    ctx.fillRect(x + w - EDGE_center_SIZE, y + h * 0.5 - EDGE_center_SIZE * 0.5, EDGE_center_SIZE, EDGE_center_SIZE)\n\n    ctx.fillRect(x, y + h - EDGE_center_SIZE, EDGE_center_SIZE, EDGE_center_SIZE)\n    ctx.fillRect(x + w * 0.5 - EDGE_center_SIZE * 0.5, y + h - EDGE_center_SIZE, EDGE_center_SIZE, EDGE_center_SIZE)\n    ctx.fillRect(x + w - EDGE_center_SIZE, y + h - EDGE_center_SIZE, EDGE_center_SIZE, EDGE_center_SIZE)\n  })\n  const imgData = canvas.toDataURL()\n  canvas.parentElement?.removeChild(canvas)\n  return imgData\n})()\n</script>\n\n<template>\n  <TresLeches style=\"position:absolute; left:10px; top:10px;\" />\n  <TresCanvas clear-color=\"#82DBC5\">\n    <TresPerspectiveCamera\n      :position=\"[5, 1, 5]\"\n      :look-at=\"[-2, 0, 0]\"\n    />\n    <OrbitControls />\n    <TresGroup :position-x=\"2\">\n      <Suspense>\n        <AnimatedSprite\n          :image=\"centerDemoImgData\"\n          :atlas=\"centerDemoAtlas\"\n          animation=\"rect\"\n          :center=\"[centerX.value, centerY.value]\"\n          :fps=\"fps.value\"\n          :as-sprite=\"asSprite.value\"\n        >\n          <TresGroup :scale=\"0.5\">\n            <Box\n              :scale=\"[1, 0.06, 0.06]\"\n              color=\"red\"\n            />\n            <Box\n              :scale=\"[0.06, 1, 0.06]\"\n              color=\"blue\"\n            />\n            <Box\n              :scale=\"[0.06, 0.06, 1]\"\n              color=\"green\"\n            />\n          </TresGroup>\n        </AnimatedSprite>\n      </Suspense>\n      <TresGridHelper :args=\"[10, 10]\" />\n    </TresGroup>\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/AnimatedSpriteDefinitionsDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { AnimatedSprite } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\n\nconst ASSETS_URL = 'https://raw.githubusercontent.com/Tresjs/'\n  + 'assets/main/textures/animated-sprite/'\n</script>\n\n<template>\n  <TresCanvas clear-color=\"#666\">\n    <TresPerspectiveCamera :position=\"[0, 0, 15]\" />\n    <Suspense>\n      <AnimatedSprite\n        :image=\"`${ASSETS_URL}cientosTexture.png`\"\n        :atlas=\"`${ASSETS_URL}cientosAtlas.json`\"\n        animation=\"cientosIdle\"\n        :definitions=\"{\n          cientosIdle: '0-5, 0(10), 1-2, 3(20), 4-5, 0-5(3)',\n        }\"\n        :fps=\"15\"\n        :loop=\"true\"\n      />\n    </Suspense>\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/AnimatedSpriteDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { AnimatedSprite } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\n\nconst ASSETS_URL = 'https://raw.githubusercontent.com/Tresjs/'\n  + 'assets/main/textures/animated-sprite/'\n</script>\n\n<template>\n  <TresCanvas clear-color=\"#FBB03B\">\n    <TresPerspectiveCamera :position=\"[0, 0, 15]\" />\n    <Suspense>\n      <AnimatedSprite\n        :image=\"`${ASSETS_URL}cientosTexture.png`\"\n        :atlas=\"`${ASSETS_URL}cientosAtlas.json`\"\n        animation=\"cientosIdle\"\n        :fps=\"15\"\n        :loop=\"true\"\n      />\n    </Suspense>\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/AnimatedSpriteNamedAnimationDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { AnimatedSprite } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { ref } from 'vue'\n\nconst ASSETS_URL = 'https://raw.githubusercontent.com/Tresjs/'\n  + 'assets/main/textures/animated-sprite/'\n\nconst animations = ref(\n  ['cientosIdle', 'cientosIdleToWalkTransition', 'cientosWalk'],\n)\n</script>\n\n<template>\n  <TresCanvas clear-color=\"#82DBC5\">\n    <TresPerspectiveCamera :position=\"[0, 0, 15]\" />\n    <Suspense>\n      <AnimatedSprite\n        :image=\"`${ASSETS_URL}cientosTexture.png`\"\n        :atlas=\"`${ASSETS_URL}cientosAtlas.json`\"\n        :animation=\"animations[0]\"\n        :fps=\"15\"\n        :loop=\"true\"\n        @click=\"() => { animations.push(animations.shift() as string) }\"\n      />\n    </Suspense>\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/BackdropDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { Backdrop, GLTFModel, useProgress } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport type { Camera } from 'three'\nimport { PCFSoftShadowMap, SRGBColorSpace } from 'three'\nimport { ref, watchEffect } from 'vue'\n\nconst gl = {\n  clearColor: 'pink',\n  shadows: true,\n  alpha: false,\n  shadowMapType: PCFSoftShadowMap,\n  outputColorSpace: SRGBColorSpace,\n}\n\nconst cameraRef = ref(null)\n\nwatchEffect(() => {\n  if (cameraRef.value) {\n    (cameraRef.value as Camera).lookAt(0, 5, 0)\n  }\n})\n\nconst { hasFinishLoading, progress } = await useProgress()\n</script>\n\n<template>\n  <div class=\"aspect-video w-full relative\">\n    <Transition\n      name=\"fade-overlay\"\n      enter-active-class=\"opacity-1 transition-opacity duration-200\"\n      leave-active-class=\"opacity-0 transition-opacity duration-200\"\n    >\n      <div\n        v-show=\"!hasFinishLoading\"\n        class=\"absolute bg-grey-600 t-0 l-0 w-full h-full z-20 flex justify-center items-center text-black font-mono\"\n      >\n        <div class=\"w-200px\">\n          Loading... {{ progress }} %\n        </div>\n      </div>\n    </Transition>\n    <TresCanvas v-bind=\"gl\">\n      <TresPerspectiveCamera\n        :position=\"[0.07224002153117198, 0.5245876539770153, 2.9469498522622626]\"\n        :rotation=\"[-0.04419077275543715, 0.025561987075415186, 0.0011302162688196786]\"\n        :fov=\"35\"\n      />\n      <Suspense>\n        <GLTFModel\n          path=\"https://raw.githubusercontent.com/Tresjs/assets/main/models/gltf/blender-cube.glb\"\n          :rotation=\"[0, 0.5, 0]\"\n          :position=\"[0, 0.4, 0]\"\n          :scale=\"0.5\"\n        />\n      </Suspense>\n      <Backdrop\n        :floor=\"1.5\"\n        :scale=\"[10, 3, 3]\"\n        :position=\"[0, 0, -3]\"\n        receive-shadow\n      >\n        <TresMeshPhysicalMaterial\n          :roughness=\"1\"\n          color=\"pink\"\n          :side=\"2\"\n        />\n      </Backdrop>\n      <TresAmbientLight :intensity=\"0.5\" />\n      <TresDirectionalLight\n        :args=\"['white', 2]\"\n        cast-shadow\n        :position=\"[3, 4, 4]\"\n        :look-at=\"[0, 0, 0]\"\n        :shadow-camera-near=\"0.5\"\n        :shadow-camera-left=\"-10\"\n      />\n      <TresDirectionalLight\n        :args=\"['pink', 1]\"\n        cast-shadow\n        :position=\"[-3, 2, 4]\"\n        :look-at=\"[0, 0, 0]\"\n        :shadow-camera-near=\"0.5\"\n        :shadow-camera-left=\"-10\"\n      />\n    </TresCanvas>\n  </div>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/BakeShadowsDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { BakeShadows } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { shallowRef } from 'vue'\n\nconst cubeRef = shallowRef()\n\nfunction onLoop({ elapsed }: { elapsed: number }) {\n  if (cubeRef.value) {\n    cubeRef.value.rotation.y = elapsed * 0.5\n    cubeRef.value.rotation.x = elapsed * 0.5\n  }\n}\n</script>\n\n<template>\n  <TresCanvas\n    clear-color=\"#82DBC5\"\n    shadows\n    @loop=\"onLoop\"\n  >\n    <TresPerspectiveCamera\n      :position=\"[0, 2, 5]\"\n      :look-at=\"[0, 0, 0]\"\n    />\n    <BakeShadows />\n    <TresMesh\n      ref=\"cubeRef\"\n      cast-shadow\n    >\n      <TresBoxGeometry />\n      <TresMeshStandardMaterial :color=\"0x00FF00\" />\n    </TresMesh>\n    <TresMesh\n      receive-shadow\n      :position=\"[0, -2, 0]\"\n      :rotation-x=\"-Math.PI / 2\"\n    >\n      <TresPlaneGeometry :args=\"[5, 5]\" />\n      <TresMeshStandardMaterial :color=\"0xF7F7F7\" />\n    </TresMesh>\n    <TresDirectionalLight\n      cast-shadow\n      :position=\"[0, 10, 0]\"\n    />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/BillboardDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { Billboard, Box, OrbitControls } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { Vector3 } from 'three'\n\nconst COUNT = 5 * 5\nconst positions = Array.from({ length: COUNT }).fill(0).map((_, i) => {\n  return new Vector3(\n    i % 5 - 2,\n    Math.floor(i / 5) - 2,\n    0,\n  )\n})\n</script>\n\n<template>\n  <TresCanvas clear-color=\"#333333\">\n    <OrbitControls />\n    <TresPerspectiveCamera :position=\"[0, 0, 10]\" />\n    <Billboard v-for=\"position, i of positions\" :key=\"i\" :position=\"position\">\n      <Box :scale=\"[0.5, 0.5, 0.001]\">\n        <TresMeshNormalMaterial />\n      </Box>\n    </Billboard>\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/BoundsDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { Bounds, OrbitControls } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { Vector3 } from 'three'\nimport { shallowRef } from 'vue'\n\nconst { sin, cos, PI } = Math\nconst positions = Array.from(\n  { length: 8 },\n  (_, i) => new Vector3(cos(i * PI / 4) * 4, sin(i * PI / 4) * 4, 0),\n)\n\nconst b = shallowRef()\n</script>\n\n<template>\n  <TresCanvas clear-color=\"#4f4f4f\">\n    <TresPerspectiveCamera :position=\"[0, 0, -15]\" />\n    <OrbitControls make-default />\n    <Bounds ref=\"b\" clip use-mounted :offset=\"0.75\">\n      <TresMesh\n        v-for=\"p, i of positions\"\n        :key=\"i\"\n        :position=\"p\"\n        @click=\"(e) => b.instance.lookAt(e.object)\"\n      >\n        <TresBoxGeometry />\n        <TresMeshNormalMaterial />\n      </TresMesh>\n    </Bounds>\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/CameraControlsDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { Box, CameraControls } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { reactive } from 'vue'\n\nconst controlsState = reactive({\n  minDistance: 0,\n  maxDistance: 100,\n})\n</script>\n\n<template>\n  <TresCanvas clear-color=\"#82DBC5\">\n    <TresPerspectiveCamera :position=\"[5, 5, 5]\" />\n    <CameraControls\n      v-bind=\"controlsState\"\n      make-default\n    />\n    <TresGridHelper :position=\"[0, -1, 0]\" />\n    <Box :scale=\"2\">\n      <TresMeshToonMaterial color=\"orange\" />\n    </Box>\n    <TresAmbientLight />\n    <TresDirectionalLight :position=\"[0, 2, 4]\" />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/CatmullRomCurve3Demo.vue",
    "content": "<script setup lang=\"ts\">\nimport { CatmullRomCurve3, OrbitControls } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\n</script>\n\n<template>\n  <TresCanvas clear-color=\"#4f4f4f\">\n    <CatmullRomCurve3\n      :points=\"[[-1.5, 0, 0], [-0.5, 1, 0], [0.5, 0, 0], [1.5, 1, 0]]\"\n      :segments=\"40\"\n      :line-width=\"10\"\n      color=\"#fbb03b\"\n    />\n    <TresGridHelper />\n    <OrbitControls />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/CientosComponentListGridView/index.vue",
    "content": "<script setup lang=\"ts\">\nimport componentList, { icons } from '../../../../component-list/components'\n</script>\n\n<template>\n  <div class=\"grid md-grid-cols-3 sm-grid-cols-2\">\n    <template v-for=\"c, i of componentList\" :key=\"i\">\n      <div>\n        <h3 class=\"text-sm\">\n          <div\n            v-if=\"c.text.toLowerCase() in icons\"\n            class=\"inline-block text-2xl p-1 p-x-2 m-r-1 m-b-5 text-2xl bg-zinc-500/10 rounded\"\n          >\n            {{ icons[c.text.toLowerCase()] }}\n          </div>\n          {{ c.text }}\n        </h3>\n        <div v-for=\"item, ii of c.items\" :key=\"ii\" class=\"m-b-2\">\n          <a :href=\"item.link\"><span class=\"text-sm font-medium\">{{ item.text }}</span></a>\n        </div>\n      </div>\n    </template>\n  </div>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/CircleShadowDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { CircleShadow, OrbitControls } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\n</script>\n\n<template>\n  <TresCanvas clear-color=\"#82DBC5\">\n    <TresPerspectiveCamera />\n    <OrbitControls />\n    <TresGroup :position-y=\"-0.5\">\n      <TresMesh :position-y=\"1\">\n        <TresBoxGeometry />\n        <TresMeshNormalMaterial />\n      </TresMesh>\n      <CircleShadow :scale=\"1.5\" />\n    </TresGroup>\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/ContactShadowsDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { ContactShadows, Levioso, TorusKnot } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\n</script>\n\n<template>\n  <TresCanvas clear-color=\"white\">\n    <Levioso :speed=\"2\" :range=\"[0, 0.7]\" :rotation-factor=\"9\">\n      <TorusKnot :scale=\"0.45\">\n        <TresMeshNormalMaterial />\n      </TorusKnot>\n    </Levioso>\n    <ContactShadows :position-y=\"-1\" color=\"#335\" :scale=\"20\" />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/CubeCameraDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { CubeCamera, OrbitControls } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { onMounted, onUnmounted, shallowRef } from 'vue'\n\nconst x = shallowRef(1)\nconst y0 = shallowRef(1)\nconst y1 = shallowRef(1)\nlet intervalId: ReturnType<typeof setInterval>\n\nlet elapsed = 0\nonMounted(() => {\n  intervalId = setInterval(() => {\n    elapsed += 1000 / 30\n    x.value = Math.cos(elapsed * 0.001) * 3\n    y0.value = (Math.sin(elapsed * 0.001) + 1) * 2\n    y1.value = (Math.sin(elapsed * 0.001 + Math.PI) + 1) * 2\n  }, 1000 / 30)\n})\n\nonUnmounted(() => { clearInterval(intervalId) })\n</script>\n\n<template>\n  <TresCanvas clear-color=\"#222\">\n    <TresPerspectiveCamera :position=\"[0, 5, 20]\" />\n    <OrbitControls />\n\n    <CubeCamera :position-y=\"5\" :resolution=\"128\">\n      <TresMesh :position=\"[-2, y0, 0]\" :scale=\"2\">\n        <TresSphereGeometry />\n        <TresMeshPhysicalMaterial :roughness=\"0\" :metalness=\"1\" />\n      </TresMesh>\n      <TresMesh :position=\"[2, y1, 0]\" :scale=\"2\">\n        <TresSphereGeometry />\n        <TresMeshPhysicalMaterial :roughness=\"0.25\" :metalness=\"1\" />\n      </TresMesh>\n    </CubeCamera>\n\n    <TresMesh :position=\"[x, 1, 0]\">\n      <TresSphereGeometry />\n      <TresMeshBasicMaterial color=\"#fbb03b\" />\n    </TresMesh>\n\n    <TresGridHelper :args=\"[100, 10]\" />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/CubicBezierLineDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { CubicBezierLine, OrbitControls } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\n</script>\n\n<template>\n  <TresLeches />\n  <TresCanvas clear-color=\"#4f4f4f\">\n    <TresPerspectiveCamera :position=\"[0, 4, 0]\" />\n    <CubicBezierLine\n      :start=\"[-1, 0, 0]\"\n      :end=\"[1, 0, 0]\"\n      :midA=\"[-1, 2, -2]\"\n      :midB=\"[1, 2, 2]\"\n      :line-width=\"10\"\n      color=\"#82dbc5\"\n    />\n    <TresGridHelper />\n    <OrbitControls />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/CustomShaderMaterialDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { CustomShaderMaterial } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { TresLeches, useControls } from '@tresjs/leches'\nimport { MeshBasicMaterial } from 'three'\n\nimport { watch } from 'vue'\nimport '@tresjs/leches/styles'\n\nconst gl = {\n  clearColor: '#82DBC5',\n}\n\nconst materialProps = {\n  baseMaterial: MeshBasicMaterial,\n  fragmentShader: `\n    varying float vWobble;\n\n    uniform float u_Time;\n\n    void main() {\n      float wobble = vWobble * 0.5 + 0.5;\n      csm_FragColor = mix(vec4(0.0, 0.4, 1.5, 1.0), vec4(1.2, 0.6, 0.8, 1.0), wobble);\n    }\n  `,\n  vertexShader: `\n    uniform float u_Time;\n    uniform float u_WobbleSpeed;\n    uniform float u_WobbleAmplitude;\n    uniform float u_WobbleFrequency;\n\n    varying float vWobble;\n\n    void main() {\n      float wobble = sin(csm_Position.z * u_WobbleFrequency + u_Time * u_WobbleSpeed);\n      csm_Position += normal * wobble * u_WobbleAmplitude;\n\n      vWobble = wobble;\n    }\n  `,\n  uniforms: {\n    u_Time: { value: 0 },\n    u_WobbleSpeed: { value: 3 },\n    u_WobbleAmplitude: { value: 0.07 },\n    u_WobbleFrequency: { value: 3 },\n  },\n}\n\nfunction onLoop() {\n  materialProps.uniforms.u_Time.value += 0.01 * materialProps.uniforms.u_WobbleSpeed.value\n}\n\nconst { speed, amplitude, frequency } = useControls({\n  speed: {\n    value: materialProps.uniforms.u_WobbleSpeed.value,\n    min: 0,\n    max: 10,\n  },\n\n  amplitude: {\n    value: materialProps.uniforms.u_WobbleAmplitude.value,\n    min: 0,\n    max: 0.2,\n    step: 0.01,\n  },\n\n  frequency: {\n    value: materialProps.uniforms.u_WobbleFrequency.value,\n    min: 1,\n    max: 30,\n  },\n})\n\nwatch([speed.value, amplitude.value, frequency.value], () => {\n  materialProps.uniforms.u_WobbleSpeed.value = speed.value.value\n  materialProps.uniforms.u_WobbleAmplitude.value = amplitude.value.value\n  materialProps.uniforms.u_WobbleFrequency.value = frequency.value.value\n})\n</script>\n\n<template>\n  <TresLeches class=\"top-0 important-left-4\" />\n  <TresCanvas v-bind=\"gl\" @loop=\"onLoop\">\n    <TresPerspectiveCamera\n      :position=\"[0, 2, 4]\"\n      :look-at=\"[-1, 0, 0]\"\n    />\n    <TresMesh>\n      <TresTorusKnotGeometry :args=\"[1, 0.3, 512, 32]\" />\n      <CustomShaderMaterial v-bind=\"materialProps\" />\n    </TresMesh>\n  </TresCanvas>\n\n  <div class=\"debug-container\"></div>\n</template>\n\n<style scoped>\n.debug-container {\n  position: absolute;\n  top: 0px;\n  right: 0px;\n}\n</style>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/DocsDemo.vue",
    "content": "<script setup lang=\"ts\">\n</script>\n\n<template>\n  <ClientOnly>\n    <div\n      class=\"relative aspect-video\"\n      style=\" height: auto; margin: 2rem 0; border-radius: 8px; overflow:hidden;\"\n    >\n      <Suspense>\n        <slot></slot>\n      </Suspense>\n    </div>\n  </ClientOnly>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/EdgesDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { TresCanvas } from '@tresjs/core'\nimport { Box, ContactShadows, Edges, OrbitControls } from '@tresjs/cientos'\nimport { MOUSE, TOUCH } from 'three'\n\nconst gl = {\n  clearColor: '#f6f6f6',\n  alpha: false,\n}\n\nconst dataBoxes = [{\n  color: '#82DBC5',\n  edgeColor: '#505050',\n}, {\n  color: '#505050',\n  edgeColor: 'white',\n}, {\n  color: '#F6B03B',\n  edgeColor: '#505050',\n}]\n</script>\n\n<template>\n  <TresCanvas\n    v-bind=\"gl\"\n  >\n    <TresPerspectiveCamera :position=\"[0, 2, 5]\" />\n    <OrbitControls\n      make-default\n      auto-rotate\n      :enableZoom=\"false\"\n      :auto-rotate-speed=\"1\"\n      :mouseButtons=\"{ LEFT: MOUSE.ROTATE, RIGHT: MOUSE.NONE }\"\n      :touches=\"{ ONE: TOUCH.ROTATE, TWO: TOUCH.NONE }\"\n    />\n\n    <Box\n      v-for=\"(x, index) in [-1.5, 0, 1.5]\"\n      :key=\"`docs-edges-demo-box-${index}`\"\n      :position=\"[x, 0, 0]\"\n    >\n      <TresMeshBasicMaterial\n        :color=\"dataBoxes[index].color\"\n      />\n      <Edges :color=\"dataBoxes[index].edgeColor\" />\n    </Box>\n\n    <ContactShadows\n      :blur=\"2\"\n      :resolution=\"512\"\n      :opacity=\".25\"\n      :position-y=\"-1\"\n    />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/EnvironmentDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { Environment, OrbitControls, Sphere, useProgress } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\n\nimport { TresLeches, useControls } from '@tresjs/leches'\nimport { BasicShadowMap, NoToneMapping, SRGBColorSpace } from 'three'\nimport { ref } from 'vue'\nimport '@tresjs/leches/styles'\n\nconst environmentFiles = ['/px.jpg', '/nx.jpg', '/py.jpg', '/ny.jpg', '/pz.jpg', '/nz.jpg']\n\nconst gl = {\n  clearColor: '#82DBC5',\n  shadows: true,\n  alpha: false,\n  shadowMapType: BasicShadowMap,\n  outputColorSpace: SRGBColorSpace,\n  toneMapping: NoToneMapping,\n}\n\nconst { background, blur } = useControls({\n  background: true,\n  blur: {\n    value: 0,\n    min: 0,\n    max: 1,\n    step: 0.01,\n  },\n}, {\n  uuid: 'environment',\n})\n\nconst environmentRef = ref(null)\n\nconst { progress, hasFinishLoading } = await useProgress()\n</script>\n\n<template>\n  <Transition\n    name=\"fade-overlay\"\n    enter-active-class=\"opacity-1 transition-opacity duration-200\"\n    leave-active-class=\"opacity-0 transition-opacity duration-200\"\n  >\n    <div\n      v-show=\"!hasFinishLoading\"\n      class=\"absolute bg-white t-0 l-0 w-full h-full z-20 flex justify-center items-center text-black font-mono\"\n    >\n      <div class=\"w-200px\">\n        Loading... {{ progress }} %\n        <i class=\"i-ic-twotone-catching-pokemon animate-rotate-in\"></i>\n      </div>\n    </div>\n  </Transition>\n  <TresLeches\n    class=\"top-0 important-left-4\"\n    uuid=\"environment\"\n  />\n  <TresCanvas v-bind=\"gl\">\n    <TresPerspectiveCamera :position=\"[7, 7, 7]\" />\n    <OrbitControls />\n    <Suspense>\n      <Environment\n        ref=\"environmentRef\"\n        :background=\"background.value\"\n        :files=\"environmentFiles\"\n        :blur=\"blur.value\"\n        path=\"https://raw.githubusercontent.com/Tresjs/assets/main/textures/environmentMap\"\n      />\n      <!-- <Environment\n        :background=\"background.value\"\n        :blur=\"blur.value\"\n        preset=\"sunset\"\n      /> -->\n    </Suspense>\n    <Sphere>\n      <TresMeshStandardMaterial\n        color=\"yellow\"\n        :roughness=\"0\"\n        :metalness=\"0.5\"\n      />\n    </Sphere>\n    <TresAmbientLight :intensity=\"1\" />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/EnvironmentPresetsDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { Environment, OrbitControls, TorusKnot, useProgress } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\n\nimport { TresLeches, useControls } from '@tresjs/leches'\nimport { BasicShadowMap, NoToneMapping, SRGBColorSpace } from 'three'\nimport { ref } from 'vue'\nimport '@tresjs/leches/styles'\n\nconst gl = {\n  clearColor: '#82DBC5',\n  shadows: true,\n  alpha: false,\n  shadowMapType: BasicShadowMap,\n  outputColorSpace: SRGBColorSpace,\n  toneMapping: NoToneMapping,\n}\n\nconst { blur, preset } = useControls({\n  background: true,\n  blur: {\n    value: 0,\n    min: 0,\n    max: 1,\n    step: 0.01,\n  },\n  preset: {\n    options: [\n      'sunset',\n      'studio',\n      'city',\n      'umbrellas',\n      'night',\n      'forest',\n      'snow',\n      'dawn',\n      'hangar',\n      'urban',\n      'modern',\n      'shangai',\n    ],\n    value: 'sunset',\n  },\n}, {\n  uuid: 'presets',\n})\n\nconst environmentRef = ref(null)\n\nconst { progress, hasFinishLoading } = await useProgress()\n</script>\n\n<template>\n  <Transition\n    name=\"fade-overlay\"\n    enter-active-class=\"opacity-1 transition-opacity duration-200\"\n    leave-active-class=\"opacity-0 transition-opacity duration-200\"\n  >\n    <div\n      v-show=\"!hasFinishLoading\"\n      class=\"absolute bg-white t-0 l-0 w-full h-full z-20 flex justify-center items-center text-black font-mono\"\n    >\n      <div class=\"w-200px\">\n        Loading... {{ progress }} %\n        <i class=\"i-ic-twotone-catching-pokemon animate-rotate-in\"></i>\n      </div>\n    </div>\n  </Transition>\n  <TresLeches\n    class=\"top-0 important-left-4\"\n    uuid=\"presets\"\n  />\n  <TresCanvas v-bind=\"gl\">\n    <TresPerspectiveCamera :position=\"[5, 5, 5]\" />\n    <OrbitControls />\n    <Suspense>\n      <Environment\n        ref=\"environmentRef\"\n        background\n        :blur=\"blur.value\"\n        :preset=\"preset.value\"\n      />\n    </Suspense>\n    <TorusKnot>\n      <TresMeshStandardMaterial\n        color=\"yellow\"\n        :roughness=\"0\"\n        :metalness=\"0.5\"\n      />\n    </TorusKnot>\n    <TresAmbientLight :intensity=\"1\" />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/FBXModelDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { FBXModel, OrbitControls } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { BasicShadowMap, NoToneMapping, SRGBColorSpace } from 'three'\n\nconst gl = {\n  clearColor: '#82DBC5',\n  shadows: true,\n  alpha: false,\n  shadowMapType: BasicShadowMap,\n  outputColorSpace: SRGBColorSpace,\n  toneMapping: NoToneMapping,\n}\n</script>\n\n<template>\n  <TresCanvas v-bind=\"gl\">\n    <TresPerspectiveCamera :position=\"[5.3, 2.45, 9.3]\" :look-at=\"[0, 0, 0]\" />\n    <OrbitControls />\n    <FBXModel\n      path=\"https://raw.githubusercontent.com/Tresjs/assets/main/models/fbx/low-poly-truck/Jeep_done.fbx\"\n      cast-shadow\n      :scale=\"0.01\"\n      :position=\"[0, -1.6, 0]\"\n      :rotation-y=\"-Math.PI * 0.5\"\n    />\n    <TresMesh\n      :rotate-x=\"Math.PI * -0.5\"\n      :position-y=\"-2\"\n      receive-shadow\n    >\n      <TresPlaneGeometry :args=\"[40, 40]\" />\n      <TresMeshStandardMaterial :color=\"0xF7F7F7\" />\n    </TresMesh>\n    <TresAmbientLight :intensity=\"1\" />\n    <TresDirectionalLight\n      :intensity=\"1\"\n      cast-shadow\n      :position=\"[5, 10, 5]\"\n    />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/FboCube.vue",
    "content": "<script setup lang=\"ts\">\nimport { useFBO } from '@tresjs/cientos'\n\nconst fboTarget = useFBO({\n  depth: true,\n  width: 512,\n  height: 512,\n  settings: {\n    samples: 1,\n  },\n})\n</script>\n\n<template>\n  <TresMesh>\n    <TresBoxGeometry :args=\"[1, 1, 1]\" />\n\n    <TresMeshBasicMaterial\n      :color=\"0xFFFFFF\"\n      :map=\"fboTarget?.texture ?? null\"\n    />\n  </TresMesh>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/FboDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { Fbo, OrbitControls } from '@tresjs/cientos'\nimport type { TresObject } from '@tresjs/core'\nimport { TresCanvas } from '@tresjs/core'\nimport { ACESFilmicToneMapping, SRGBColorSpace } from 'three'\nimport { ref, shallowReactive, shallowRef } from 'vue'\n\nconst gl = {\n  clearColor: '#82DBC5',\n  shadows: true,\n  alpha: false,\n  outputColorSpace: SRGBColorSpace,\n  toneMapping: ACESFilmicToneMapping,\n}\n\nconst fboRef = ref(null)\nconst torusRef = shallowRef<TresObject | null>(null)\nconst capsuleRef = shallowRef<TresObject | null>(null)\n\nconst state = shallowReactive({\n  depth: false,\n  settings: {\n    samples: 1,\n  },\n})\n\nfunction onLoop({ elapsed }: { elapsed: number }) {\n  if (!torusRef.value || !capsuleRef.value) { return }\n\n  torusRef.value.rotation.x = elapsed * 0.745\n  torusRef.value.rotation.y = elapsed * 0.361\n\n  capsuleRef.value.rotation.x = elapsed * 0.471\n  capsuleRef.value.rotation.z = elapsed * 0.632\n}\n</script>\n\n<template>\n  <TresCanvas v-bind=\"gl\" @loop=\"onLoop\">\n    <TresPerspectiveCamera :position=\"[0, 0.5, 5]\" />\n    <OrbitControls />\n\n    <TresGridHelper :args=\"[10, 10]\" />\n\n    <Fbo\n      ref=\"fboRef\"\n      v-bind=\"state\"\n    />\n\n    <TresMesh>\n      <TresBoxGeometry :args=\"[1, 1, 1]\" />\n\n      <TresMeshBasicMaterial\n        :color=\"0xFFFFFF\"\n        :map=\"fboRef?.instance.texture ?? null\"\n      />\n    </TresMesh>\n\n    <TresMesh\n      ref=\"torusRef\"\n      :position=\"[3, 0, 0]\"\n    >\n      <TresTorusGeometry :args=\"[1, 0.5, 16, 100]\" />\n      <TresMeshNormalMaterial />\n    </TresMesh>\n\n    <TresMesh\n      ref=\"capsuleRef\"\n      :position=\"[-2, 0, 0]\"\n    >\n      <TresCapsuleGeometry :args=\"[0.4, 1, 4, 8]\" />\n      <TresMeshNormalMaterial />\n    </TresMesh>\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/Feather.vue",
    "content": "<script setup lang=\"ts\">\nimport { Levioso, useGLTF } from '@tresjs/cientos'\nimport { shallowRef, watchEffect } from 'vue'\n\nconst { state } = useGLTF('/feather.glb')\n\nconst featherRef = shallowRef()\n\nwatchEffect(() => {\n  if (featherRef.value) {\n    featherRef.value.rotation.y = -Math.PI / 4\n    featherRef.value.updateMatrixWorld()\n  }\n})\n</script>\n\n<template>\n  <Levioso\n    :speed=\"4\"\n  >\n    <primitive\n      v-if=\"state?.scene\"\n      ref=\"featherRef\"\n      :object=\"state?.scene\"\n      :position-y=\"-Math.PI / 4\"\n    />\n  </Levioso>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/FitDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { Fit, OrbitControls } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { BoxGeometry, MeshNormalMaterial } from 'three'\n\nconst positions: number[][] = []\nfor (let y = 100; y <= 120; y += 10) {\n  for (let x = 100; x <= 120; x += 10) {\n    positions.push([x, y, 9999])\n  }\n}\nconst geom = new BoxGeometry()\nconst mat = new MeshNormalMaterial()\n</script>\n\n<template>\n  <TresCanvas clear-color=\"#4F4F4F\">\n    <TresPerspectiveCamera :position=\"[1, 1, 1]\" />\n    <OrbitControls />\n    <Fit>\n      <TresMesh\n        v-for=\"(p, i) in positions\"\n        :key=\"i\"\n        :position=\"p\"\n        :args=\"[geom, mat]\"\n      />\n    </Fit>\n    <TresGridHelper :args=\"[1, 1]\" />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/GLTFModelDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { GLTFModel, OrbitControls } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\n</script>\n\n<template>\n  <TresCanvas clear-color=\"#F78B3D\">\n    <TresPerspectiveCamera :position=\"[3, 2, 5]\" />\n    <OrbitControls />\n    <GLTFModel path=\"https://raw.githubusercontent.com/Tresjs/assets/main/models/gltf/blender-cube.glb\" />\n    <TresDirectionalLight\n      :intensity=\"2\"\n      :position=\"[3, 3, 3]\"\n    />\n    <TresAmbientLight :intensity=\"1\" />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/GlassMaterialDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { MeshGlassMaterial, OrbitControls } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\n</script>\n\n<template>\n  <TresCanvas clear-color=\"#82DBC5\">\n    <TresPerspectiveCamera :position=\"[3, 3, 3]\" />\n    <TresMesh>\n      <TresTorusKnotGeometry :args=\"[1, 0.4, 256, 20]\" />\n      <MeshGlassMaterial />\n    </TresMesh>\n    <TresMesh :position=\"[0, 0, -1]\">\n      <TresPlaneGeometry :args=\"[5, 5]\" />\n      <TresMeshBasicMaterial :color=\"0xFF1111\" />\n    </TresMesh>\n    <TresGridHelper :args=\"[10, 10]\" />\n    <TresAmbientLight />\n    <TresDirectionalLight :position=\"[2, 2, 2]\" />\n    <OrbitControls />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/GradientTextureDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { TresCanvas } from '@tresjs/core'\nimport { GradientTexture } from '@tresjs/cientos'\n</script>\n\n<template>\n  <TresCanvas clear-color=\"#e3e3e3\">\n    <TresPerspectiveCamera :position=\"[0, 0, 3]\" />\n    <TresMesh>\n      <TresPlaneGeometry />\n      <TresMeshBasicMaterial>\n        <GradientTexture :stops=\"[0.1, 0.5, 0.9]\" :colors=\"['#4f4f4f', '#82dbc5', '#fbb03b']\" />\n      </TresMeshBasicMaterial>\n    </TresMesh>\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/GridDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { Grid, OrbitControls } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\n</script>\n\n<template>\n  <TresCanvas clear-color=\"#222222\">\n    <TresPerspectiveCamera :position=\"[8, 10, 10]\" :fov=\"25\" />\n    <OrbitControls />\n    <Grid\n      :args=\"[10.5, 10.5]\"\n      cell-color=\"#82dbc5\"\n      :cell-size=\"0.6\"\n      :cell-thickness=\"0.5\"\n      section-color=\"#fbb03b\"\n      :section-size=\"2\"\n      :section-thickness=\"1.3\"\n      :infinite-grid=\"true\"\n      :fade-from=\"0\"\n      :fade-distance=\"12\"\n      :fade-strength=\"1\"\n    />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/HelperDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { BoxHelper, PointLightHelper } from 'three'\nimport { VertexNormalsHelper } from 'three-stdlib'\nimport { Helper, OrbitControls } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\n</script>\n\n<template>\n  <TresCanvas clear-color=\"#222\">\n    <TresPerspectiveCamera :position=\"[10, 10, 10]\" />\n    <OrbitControls />\n\n    <TresPointLight :position=\"[5, 5, -5]\">\n      <Helper :type=\"PointLightHelper\" :args=\"[0.5]\" />\n    </TresPointLight>\n\n    <TresGroup>\n      <Helper :type=\"BoxHelper\" :args=\"['royalblue']\" />\n\n      <TresMesh :position=\"[-2, 2, -1]\">\n        <TresSphereGeometry />\n        <TresMeshBasicMaterial />\n        <Helper :type=\"BoxHelper\" :args=\"['red']\" />\n      </TresMesh>\n\n      <TresMesh :position=\"[2, -2, 1]\">\n        <TresBoxGeometry />\n        <TresMeshBasicMaterial />\n        <Helper :type=\"VertexNormalsHelper\" :args=\"[1, 'red']\" />\n      </TresMesh>\n    </TresGroup>\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/HolographicMaterialDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { HolographicMaterial, Levioso, OrbitControls, useGLTF } from '@tresjs/cientos'\nimport type { TresObject } from '@tresjs/core'\nimport { TresCanvas } from '@tresjs/core'\nimport { shallowRef, watch } from 'vue'\n\nconst path = 'https://raw.githubusercontent.com/'\n  + 'Tresjs/assets/main/models/gltf/aku-aku/AkuAku.gltf'\nconst { state } = useGLTF(path)\n\nconst holographicMaterialRef = shallowRef()\n\nwatch(holographicMaterialRef, (value) => {\n  state.value?.scene?.traverse((child: TresObject) => {\n    if (child.isMesh) {\n      child.material.dispose()\n      child.material = value.root\n    }\n  })\n})\n</script>\n\n<template>\n  <TresCanvas clear-color=\"#333\">\n    <TresPerspectiveCamera :position=\"[0, 0, 6]\" />\n    <Levioso :speed=\"5\">\n      <primitive\n        v-if=\"state?.scene\"\n        :object=\"state?.scene\"\n        :position-y=\"-2.5\"\n      >\n        <HolographicMaterial ref=\"holographicMaterialRef\" />\n      </primitive>\n    </Levioso>\n    <OrbitControls />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/HtmlDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { Html, OrbitControls } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\n\nconst gl = {\n  clearColor: '#82DBC5',\n  shadows: true,\n}\n</script>\n\n<template>\n  <TresCanvas v-bind=\"gl\">\n    <TresPerspectiveCamera :position=\"[3, 3, 8]\" />\n    <OrbitControls />\n    <TresMesh :position=\"[1, 1, 1]\">\n      <TresBoxGeometry />\n      <TresMeshNormalMaterial />\n      <Html\n        center\n        transform\n        :distance-factor=\"4\"\n        :position=\"[0, 0, 0.65]\"\n        :scale=\"[0.75, 0.75, 0.75]\"\n      >\n        <h1 class=\"bg-white dark:bg-dark text-xs p-1 rounded\">\n          I'm a Box 📦\n        </h1>\n      </Html>\n    </TresMesh>\n    <TresGridHelper />\n    <TresAmbientLight />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/HtmlLaptopDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { ContactShadows, Html, OrbitControls, useGLTF } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\n\nconst gl = {\n  clearColor: '#241a1a',\n  shadows: true,\n}\n\nconst { state }\n  = useGLTF('https://vazxmixjsiawhamofees.supabase.co/storage/v1/object/public/models/macbook/model.gltf', { draco: true })\n</script>\n\n<template>\n  <TresCanvas v-bind=\"gl\">\n    <TresPerspectiveCamera :position=\"[-5, 4, 3]\" />\n    <OrbitControls />\n\n    <primitive v-if=\"state?.nodes\" :object=\"state?.nodes.Macbook\">\n      <Html\n        transform\n        wrapper-class=\"webpage\"\n        :distance-factor=\"11\"\n        :position=\"[0, 8, -11]\"\n        occlude\n        :rotation-x=\"-0.256\"\n      >\n        <iframe\n          class=\"rounded-lg w-[1024px] h-[670px]\"\n          src=\"https://tresjs.org\"\n          frameborder=\"0\"\n        ></iframe>\n      </Html>\n    </primitive>\n\n    <ContactShadows\n      :blur=\"3.5\"\n      :resolution=\"512\"\n      :opacity=\"1\"\n    />\n    <TresAmbientLight :intensity=\"1\" />\n    <TresDirectionalLight\n      :intensity=\"2\"\n      :position=\"[2, 3, 0]\"\n      :cast-shadow=\"true\"\n      :shadow-camera-far=\"50\"\n      :shadow-camera-left=\"-10\"\n      :shadow-camera-right=\"10\"\n      :shadow-camera-top=\"10\"\n      :shadow-camera-bottom=\"-10\"\n    />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/HtmlOccludeDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { Html, OrbitControls } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { ref } from 'vue'\n\nconst gl = {\n  clearColor: '#82DBC5',\n  shadows: true,\n}\n\nconst sphereRef = ref(null)\n</script>\n\n<template>\n  <TresCanvas v-bind=\"gl\">\n    <TresPerspectiveCamera :position=\"[3, 3, 8]\" />\n    <OrbitControls />\n    <TresMesh :position=\"[1, 1, 1]\">\n      <TresBoxGeometry />\n      <TresMeshNormalMaterial />\n      <Html\n        center\n        transform\n        :occlude=\"[sphereRef]\"\n        :distance-factor=\"4\"\n      >\n        <h1 class=\"bg-white dark:bg-dark text-xs p-1 rounded\">\n          Move camera\n        </h1>\n      </Html>\n    </TresMesh>\n    <TresMesh\n      ref=\"sphereRef\"\n      :position=\"[3, 1, 1]\"\n    >\n      <TresSphereGeometry />\n      <TresMeshNormalMaterial />\n      <Html\n        center\n        transform\n        :distance-factor=\"4\"\n      >\n        <h1 class=\"bg-white dark:bg-dark text-xs p-1 rounded\">\n          Sphere\n        </h1>\n      </Html>\n    </TresMesh>\n    <TresGridHelper />\n    <TresAmbientLight :intensity=\"1\" />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/ImageDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { NoToneMapping, SRGBColorSpace } from 'three'\nimport { TresCanvas } from '@tresjs/core'\nimport { Image, OrbitControls } from '@tresjs/cientos'\n\nconst gl = {\n  clearColor: '#82DBC5',\n  outputColorSpace: SRGBColorSpace,\n  toneMapping: NoToneMapping,\n}\n\nconst URL_STUB = 'https://upload.wikimedia.org/wikipedia/commons/'\n\nconst URLS = [\n  'f/f0/Cyanistes_caeruleus_Oulu_20150516.JPG',\n  '3/36/Cyanistes_caeruleus_Oulu_20130323.JPG',\n  '2/2e/Cyanistes_caeruleus_Oulu_20170507_02.jpg',\n].map(url => URL_STUB + url)\n</script>\n\n<template>\n  <TresCanvas\n    v-bind=\"gl\"\n  >\n    <TresPerspectiveCamera :position=\"[0, 0, 2]\" />\n    <OrbitControls />\n    <Image :url=\"URLS[0]\" :radius=\"0.2\" :transparent=\"true\" :position=\"[-1.5, 0, -1]\" />\n    <Image :url=\"URLS[1]\" :radius=\"0.2\" :transparent=\"true\" />\n    <Image :url=\"URLS[2]\" :radius=\"0.2\" :transparent=\"true\" :position=\"[1.5, 0, -1]\" />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/KeyboardControlsDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { Box, KeyboardControls } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\n</script>\n\n<template>\n  <TresCanvas>\n    <TresPerspectiveCamera />\n    <Box :position-y=\"0.5\" />\n    <KeyboardControls />\n    <TresGridHelper />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/LODDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { LOD } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { BoxGeometry, IcosahedronGeometry, MeshBasicMaterial, Vector3 } from 'three'\nimport { onMounted, onUnmounted, ref } from 'vue'\n\nconst COUNT = 1000\nconst positions = Array.from({ length: COUNT }).fill(0).map((_, i) => {\n  return new Vector3(\n    Math.cos(i) * 1000,\n    Math.sin(i) * 1000,\n    8000 * (2 * i / COUNT - 1),\n  )\n})\n\nconst geometries = [\n  new IcosahedronGeometry(100, 4),\n  new IcosahedronGeometry(100, 0),\n  new BoxGeometry(100, 100, 100),\n]\n\nconst materials = [\n  new MeshBasicMaterial({ color: '#fbb03b', wireframe: true }),\n  new MeshBasicMaterial({ color: '#82dbc5', wireframe: true }),\n  new MeshBasicMaterial({ color: '#4f4f4f', wireframe: true }),\n]\n\nconst z = ref(0)\nlet intervalId: ReturnType<typeof setInterval>\nlet elapsed = 0\n\nonMounted(() => {\n  intervalId = setInterval(() => {\n    elapsed += 0.005\n    z.value = Math.cos(elapsed) * 5000\n  }, 1000 / 30)\n})\n\nonUnmounted(() => {\n  clearInterval(intervalId)\n})\n</script>\n\n<template>\n  <TresCanvas clear-color=\"gray\">\n    <TresPerspectiveCamera :near=\"1\" :far=\"25000\" :position=\"[0, 0, 0]\" />\n    <TresGroup :position-z=\"z\">\n      <LOD v-for=\"position, i of positions\" :key=\"i\" :levels=\"[1500, 3000, 4000]\" :position=\"position\">\n        <TresMesh :geometry=\"geometries[0]\" :material=\"materials[0]\" />\n        <TresMesh :geometry=\"geometries[1]\" :material=\"materials[1]\" />\n        <TresMesh :geometry=\"geometries[2]\" :material=\"materials[2]\" />\n      </LOD>\n    </TresGroup>\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/LensflareDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { Lensflare, OrbitControls, Torus } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { TresLeches, useControls } from '@tresjs/leches'\nimport { shallowRef } from 'vue'\nimport '@tresjs/leches/styles'\n\nconst [x, z] = [shallowRef(0), shallowRef(0)]\n\nfunction onLoop({ elapsed }: { elapsed: number }) {\n  z.value = Math.cos(elapsed * 0.5) * 2\n  x.value = Math.sin(elapsed)\n}\n\nconst { value: scale } = useControls({\n  scale: { value: 0.33, min: 0.01, max: 2, step: 0.01 },\n})\n</script>\n\n<template>\n  <TresLeches class=\"important-top-4 important-left-4\" />\n  <TresCanvas clear-color=\"#333\" @loop=\"onLoop\">\n    <OrbitControls />\n    <TresPointLight :position=\"[x, 0, z]\">\n      <Lensflare\n        :seed=\"1028\"\n        :scale=\"scale\"\n      />\n    </TresPointLight>\n    <Torus\n      v-for=\"n in [-2, 0, 2]\"\n      :key=\"n\"\n      :args=\"[0.7, 0.15]\"\n      :position-z=\"n\"\n      :rotation-y=\"Math.PI * 0.5\"\n    >\n      <TresMeshPhongMaterial color=\"#888\" />\n    </Torus>\n    <TresGridHelper :position=\"[0, -0.9, 0]\" />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/LeviosoDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { OrbitControls } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { BasicShadowMap, NoToneMapping, SRGBColorSpace } from 'three'\nimport Feather from './Feather.vue'\n\nconst gl = {\n  clearColor: '#82DBC5',\n  shadows: true,\n  alpha: false,\n  shadowMapType: BasicShadowMap,\n  outputColorSpace: SRGBColorSpace,\n  toneMapping: NoToneMapping,\n}\n</script>\n\n<template>\n  <TresCanvas\n    v-bind=\"gl\"\n  >\n    <TresPerspectiveCamera :position=\"[1, 2, 1]\" />\n    <Suspense>\n      <Feather />\n    </Suspense>\n    <TresAmbientLight :intensity=\"1\" />\n    <TresDirectionalLight\n      :intensity=\"1\"\n      :position=\"[2, 2, 2]\"\n    />\n    <OrbitControls />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/Line2Demo.vue",
    "content": "<script setup lang=\"ts\">\nimport { Line2, OrbitControls } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\n</script>\n\n<template>\n  <TresCanvas v-bind=\"{ clearColor: '#4f4f4f' }\">\n    <Line2\n      :points=\"[[-0.5, 0, 0], [0.5, 0, 0], [0, 0.8660, 0], [-0.5, 0, 0]]\"\n      :line-width=\"10\"\n      color=\"#82dbc5\"\n    />\n    <TresGridHelper />\n    <OrbitControls />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/LoveVueThreeJS.vue",
    "content": "<script setup lang=\"ts\">\n/// <reference types=\"vite-svg-loader\" />\nimport { gsap } from 'gsap'\nimport { onMounted, ref } from 'vue'\nimport SecondRow from '../assets/second-row.svg'\nimport ThirdRow from '../assets/third-row.svg'\nimport Triangle from '../assets/triangle.svg'\n\nconst triangleRef = ref()\nconst secondRowRef = ref()\nconst thirdRowRef = ref()\n\nconst tl2r = gsap.timeline()\nconst tl3r = gsap.timeline()\n\nconst heightOfSignleSvg = 150\n\nasync function restartAnimation() {\n  gsap.to(secondRowRef.value.$el, {\n    duration: 1,\n    y: 0,\n    ease: 'elastic.out(0.7, 0.2)',\n  })\n  await gsap.to(thirdRowRef.value.$el, {\n    delay: 0.65,\n    duration: 1,\n    y: 0,\n    ease: 'steps(4)',\n  })\n\n  tl2r.restart()\n  tl3r.restart()\n}\n\nonMounted(() => {\n  tl2r.to(secondRowRef.value.$el, {\n    delay: 1,\n    duration: 2,\n    y: -(8 * heightOfSignleSvg),\n    ease: 'elastic.easeOut',\n  })\n  tl3r.to(thirdRowRef.value.$el, {\n    delay: 1.25,\n    duration: 2,\n    y: -(12 * heightOfSignleSvg),\n    ease: 'power1.out',\n  })\n})\n</script>\n\n<template>\n  <div\n    class=\"grid items-center w-full min-w-370px -translate-x-20px md:translate-x-20px h-full scale-75\"\n    @click=\"restartAnimation\"\n  >\n    <div class=\"grid grid-cols-3 gap-8 overflow-hidden h-93px\">\n      <Triangle ref=\"triangleRef\" />\n      <SecondRow ref=\"secondRowRef\" />\n      <ThirdRow ref=\"thirdRowRef\" />\n    </div>\n  </div>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/MapControlsDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { MapControls, Sphere } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\n</script>\n\n<template>\n  <TresCanvas clear-color=\"#82DBC5\">\n    <TresPerspectiveCamera :position=\"[3, 3, 3]\" />\n    <MapControls />\n    <TresGridHelper />\n    <Sphere :scale=\"0.5\">\n      <TresMeshNormalMaterial />\n    </Sphere>\n    <TresAmbientLight :intensity=\"1\" />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/MarchingCubesDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { MarchingCube, MarchingCubes, MarchingPlane, OrbitControls } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { NoToneMapping, Vector3 } from 'three'\n\nconst rand = () => (Math.random() - 0.5) * 1.25\nconst positions = Array.from({ length: 40 }, () => new Vector3(rand(), rand(), rand()))\n</script>\n\n<template>\n  <TresCanvas clear-color=\"#222\" :tone-mapping=\"NoToneMapping\">\n    <TresPerspectiveCamera />\n    <OrbitControls />\n\n    <MarchingCubes :resolution=\"40\" :max-poly-count=\"40000\">\n      <MarchingPlane plane-type=\"y\" />\n      <MarchingCube\n        v-for=\"position, i of positions\"\n        :key=\"i\"\n        :position=\"position\"\n      />\n      <TresMeshPhongMaterial specular=\"#111111\" :shininess=\"30\" color=\"#049ef4\" :reflectivity=\"1\" />\n    </MarchingCubes>\n\n    <TresAxesHelper />\n    <TresDirectionalLight color=\"#ffffff\" :intensity=\"3\" :position=\"[0, 200, 0]\" />\n    <TresDirectionalLight color=\"#ffffff\" :intensity=\"3\" :position=\"[100, 200, 100]\" />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/MaskDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { NoToneMapping } from 'three'\nimport { Mask, OrbitControls, useMask } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\n</script>\n\n<template>\n  <TresLeches />\n  <TresCanvas :tone-mapping=\"NoToneMapping\" :stencil=\"true\" clear-color=\"#4f4f4f\">\n    <TresPerspectiveCamera />\n    <OrbitControls />\n\n    <TresGroup :scale=\"2\">\n      <TresMesh>\n        <TresRingGeometry :args=\"[0.95, 1, 64]\" />\n        <TresMeshBasicMaterial color=\"white\" />\n      </TresMesh>\n      <Mask>\n        <TresCircleGeometry />\n        <TresMeshBasicMaterial color=\"#fbb03b\" />\n      </Mask>\n    </TresGroup>\n\n    <TresMesh :position-z=\"-1\">\n      <TresBoxGeometry />\n      <TresMeshNormalMaterial v-bind=\"useMask(1)\" />\n    </TresMesh>\n\n    <TresMesh :position-z=\"-3\">\n      <TresBoxGeometry />\n      <TresMeshNormalMaterial v-bind=\"useMask(1)\" />\n    </TresMesh>\n\n    <TresMesh :position-z=\"-5\">\n      <TresBoxGeometry />\n      <TresMeshNormalMaterial />\n    </TresMesh>\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/MeshReflectionMaterialDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { MeshReflectionMaterial, UseSVG as MySVG, OrbitControls, useTexture } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\n\nconst normalMapSrc = 'https://raw.githubusercontent.com/'\n  + 'Tresjs/assets/main/textures/rock/normal.jpg'\nconst { state: normalMap } = useTexture(normalMapSrc)\nconst svgSrc = '/logo.svg'\n</script>\n\n<template>\n  <Suspense>\n    <TresCanvas clear-color=\"white\">\n      <TresMesh :rotation-x=\"-Math.PI / 2\">\n        <TresPlaneGeometry :args=\"[30, 30]\" />\n        <MeshReflectionMaterial\n          :roughness=\"0\"\n          :normal-map=\"normalMap\"\n        />\n      </TresMesh>\n      <TresPerspectiveCamera :position=\"[0, 2, 20]\" />\n      <OrbitControls />\n      <MySVG\n        :src=\"svgSrc\"\n        :position=\"[-8.0, 4, 0]\"\n        :scale=\"0.04\"\n        :depth=\"1\"\n      />\n    </TresCanvas>\n  </Suspense>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/MouseParallaxDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { MouseParallax, TorusKnot } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\n</script>\n\n<template>\n  <TresCanvas clear-color=\"#82DBC5\">\n    <TresPerspectiveCamera\n      :position=\"[0, 0, 7.5]\"\n      :fov=\"75\"\n    />\n    <TorusKnot>\n      <TresMeshNormalMaterial />\n    </TorusKnot>\n    <MouseParallax\n      :factor=\"5\"\n      :ease=\"[3, 0.1]\"\n    />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/OceanDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { Ocean, OrbitControls, Sky } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\n</script>\n\n<template>\n  <TresCanvas>\n    <TresPerspectiveCamera :position=\"[0, 1, 1]\" />\n    <Sky :azimuth=\"0\" />\n    <Suspense>\n      <Ocean />\n    </Suspense>\n    <TresMesh :position-y=\"1\">\n      <TresBoxGeometry :args=\"[1, 1, 1]\" />\n    </TresMesh>\n    <OrbitControls\n      :enable-pan=\"false\"\n      :enable-zoom=\"false\"\n      :max-polar-angle=\"Math.PI * 0.495\"\n      :min-distance=\"40.0\"\n      :max-distance=\"200.0\"\n    />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/OrbitControlsDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { Box, OrbitControls } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\n</script>\n\n<template>\n  <TresCanvas clear-color=\"#82DBC5\">\n    <TresPerspectiveCamera :position=\"[3, 3, 3]\" />\n    <OrbitControls />\n    <Box :scale=\"2\">\n      <TresMeshToonMaterial color=\"orange\" />\n    </Box>\n    <TresAmbientLight />\n    <TresDirectionalLight\n      :position=\"[0, 2, 4]\"\n    />\n    <TresGridHelper />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/OutlineDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { TresCanvas } from '@tresjs/core'\nimport { OrbitControls, Outline } from '@tresjs/cientos'\n</script>\n\n<template>\n  <TresCanvas clear-color=\"#4f4f4f\">\n    <TresPerspectiveCamera />\n    <OrbitControls />\n    <TresAmbientLight :intensity=\"3.14\" />\n    <TresPointLight :intensity=\"50\" :position=\"[2, 2, 0]\" />\n    <TresMesh :position-x=\"-0.75\">\n      <TresBoxGeometry />\n      <TresMeshPhongMaterial />\n      <Outline :thickness=\"7.5\" color=\"#82dbc5\" />\n    </TresMesh>\n    <TresMesh :position-x=\"0.75\">\n      <TresSphereGeometry :args=\"[0.5]\" />\n      <TresMeshPhongMaterial />\n      <Outline :thickness=\"7.5\" color=\"#fbb03b\" />\n    </TresMesh>\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/PBRTexturesDemo.vue",
    "content": "<script setup lang=\"ts\">\n/* eslint-disable no-console */\nimport { computed, watch } from 'vue'\nimport { TresCanvas } from '@tresjs/core'\nimport { Environment, OrbitControls, useGLTF, useTextures } from '@tresjs/cientos'\nimport type { MeshStandardMaterial } from 'three'\n\n// Load the 3D model\nconst { nodes, materials } = useGLTF('https://raw.githubusercontent.com/Tresjs/assets/main/models/gltf/blender-cube.glb', { draco: true })\nconst cube = computed(() => nodes.value?.BlenderCube)\nconst material = computed(() => materials.value?.Material)\n\n// Define texture paths\nconst texturePaths = [\n  'https://raw.githubusercontent.com/Tresjs/assets/main/textures/rusted-metal/Metal053C_4K-JPG_Color.jpg',\n  'https://raw.githubusercontent.com/Tresjs/assets/main/textures/rusted-metal/Metal053C_4K-JPG_NormalGL.jpg',\n  'https://raw.githubusercontent.com/Tresjs/assets/main/textures/rusted-metal/Metal053C_4K-JPG_Roughness.jpg',\n  'https://raw.githubusercontent.com/Tresjs/assets/main/textures/rusted-metal/Metal053C_4K-JPG_Metalness.jpg',\n  'https://raw.githubusercontent.com/Tresjs/assets/main/textures/rusted-metal/Metal053C_4K-JPG_Displacement.jpg',\n]\n\n// Load all PBR textures at once\nconst { textures, isLoading, error } = useTextures(texturePaths)\n\n// Apply textures to material when loaded\nwatch([material, textures], ([modelMaterial, textures]) => {\n  if (modelMaterial && textures && textures.length === texturePaths.length) {\n    // Cast to MeshStandardMaterial to access PBR properties\n    const pbrMaterial = modelMaterial as MeshStandardMaterial\n\n    // Apply textures\n    pbrMaterial.map = textures[0]\n    pbrMaterial.normalMap = textures[1]\n    pbrMaterial.roughnessMap = textures[2]\n    pbrMaterial.metalnessMap = textures[3]\n    pbrMaterial.displacementMap = textures[4]\n\n    // Set material properties\n    pbrMaterial.displacementScale = 0\n    pbrMaterial.metalness = 0.8\n    pbrMaterial.roughness = 0.2\n  }\n})\n\n// Log loading state and errors\nwatch(isLoading, (_loading) => {\n  console.log('isLoading', _loading)\n}, { immediate: true })\n\nwatch(error, (errs) => {\n  if (errs) {\n    console.error('Error loading textures:', errs)\n  }\n})\n</script>\n\n<template>\n  <Transition\n    name=\"fade-overlay\"\n    enter-active-class=\"opacity-1 transition-opacity duration-200\"\n    leave-active-class=\"opacity-0 transition-opacity duration-200\"\n  >\n    <div\n      v-show=\"isLoading\"\n      class=\"absolute bg-white t-0 l-0 w-full h-full z-20 flex justify-center items-center text-black font-mono\"\n    >\n      <div class=\"w-200px\">\n        Loading...\n      </div>\n    </div>\n  </Transition>\n  <TresCanvas clear-color=\"#4f4f4f\">\n    <Suspense>\n      <Environment preset=\"studio\" background :blur=\"1\" />\n    </Suspense>\n    <TresPerspectiveCamera :position=\"[2, 2, 4]\" :look-at=\"[0, 2, 0]\" />\n    <OrbitControls :target=\"[0, 2, 0]\" />\n    <TresGridHelper />\n    <TresAmbientLight :intensity=\"2\" />\n    <TresGroup position-y=\"2\">\n      <primitive v-if=\"cube\" :object=\"cube\" />\n    </TresGroup>\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/PointMaterialDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { MathUtils, NoToneMapping } from 'three'\nimport { TresCanvas } from '@tresjs/core'\nimport { OrbitControls, PointMaterial } from '@tresjs/cientos'\n\nconst positions = new Float32Array(Array.from({ length: 100 }, () => [\n  MathUtils.randFloatSpread(8),\n  MathUtils.randFloatSpread(8),\n  MathUtils.randFloatSpread(8),\n]).flat())\n</script>\n\n<template>\n  <TresCanvas :tone-mapping=\"NoToneMapping\" clear-color=\"#4F4F4F\" :raycaster=\"{ params: { Points: { threshold: 0.2 } } }\">\n    <TresPerspectiveCamera :position=\"[10, 10, 10]\" />\n    <OrbitControls />\n    <TresPoints :limit=\"positions.length\">\n      <PointMaterial\n        color=\"#82dbc5\"\n        :transparent=\"true\"\n        :size=\"10\"\n        :size-attenuation=\"false\"\n        :depth-test=\"false\"\n        :tone-mapped=\"false\"\n      />\n      <TresBufferGeometry>\n        <TresBufferAttribute :args=\"[positions, 3]\" attach=\"attributes-position\" />\n      </TresBufferGeometry>\n    </TresPoints>\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/PositionalAudioDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { OrbitControls, PositionalAudio, Sphere, useGLTF } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { TresLeches, useControls } from '@tresjs/leches'\nimport { gsap } from 'gsap'\nimport { onMounted, onUnmounted, ref, shallowRef, watch } from 'vue'\nimport '@tresjs/leches/styles'\n\nconst gl = {\n  clearColor: '#FAFAFA',\n  shadows: true,\n}\n\nlet tl: gsap.core.Timeline, ctx: gsap.Context\n\nconst ready = ref(false)\nconst positionalAudioRef = shallowRef(null)\nconst ballRef = shallowRef(null)\n\nconst { helper, innerAngle, outerAngle, outerGain } = useControls({\n  helper: true,\n  innerAngle: {\n    label: 'innerAngle',\n    value: 195,\n    min: 0,\n    max: 360,\n    step: 1,\n  },\n  outerAngle: {\n    label: 'outerAngle',\n    value: 260,\n    min: 0,\n    max: 360,\n    step: 1,\n  },\n  outerGain: {\n    label: 'outerGain',\n    value: 0.3,\n    min: 0,\n    max: 1,\n    step: 0.01,\n  },\n})\n\nconst { state } = useGLTF('https://raw.githubusercontent.com/Tresjs/assets/main/models/gltf/positional-audio/ping-pong.glb', { draco: true })\n\nconst onBallBounce = () => {\n  const iteration = tl.iteration() % 2\n\n  if (!iteration) {\n    positionalAudioRef?.value?.play()\n  }\n}\n\nwatch(helper.value, () => {\n  innerAngle.value.visible = outerAngle.value.visible = outerGain.value.visible = helper.value.value\n})\n\nwatch([ready], () => {\n  if (!ballRef?.value || !ready.value) { return }\n\n  ctx.add(() => {\n    tl = gsap\n      .timeline({ repeat: -1, yoyo: true, onRepeat: onBallBounce })\n      .to(ballRef.value.instance.position, { y: 0, ease: 'power1.in', duration: 0.35 })\n  })\n})\n\nonMounted(() => {\n  ctx = gsap.context(() => { })\n})\n\nonUnmounted(() => {\n  positionalAudioRef?.value?.dispose()\n  ctx?.revert()\n})\n</script>\n\n<template>\n  <TresLeches class=\"important-left-initial important-right-2 important-w-220px\" />\n\n  <div\n    v-if=\"!ready\"\n    class=\"ready\"\n  >\n    <button @click=\"ready = true\">\n      click to continue\n    </button>\n  </div>\n\n  <div\n    v-if=\"ready\"\n    class=\"controls\"\n  >\n    <button @click=\"tl?.play()\">\n      play\n    </button>\n    <button @click=\"tl?.pause()\">\n      pause\n    </button>\n  </div>\n\n  <TresCanvas\n    v-bind=\"gl\"\n  >\n    <TresPerspectiveCamera :position=\"[0, 0.5, 15]\" />\n    <OrbitControls make-default />\n\n    <Sphere\n      ref=\"ballRef\"\n      :args=\"[1, 16, 16]\"\n      :position=\"[0, 3, 0]\"\n      :rotation-x=\"Math.PI / -2\"\n      cast-shadow\n      receive-shadow\n    >\n      <TresMeshStandardMaterial />\n\n      <Suspense>\n        <PositionalAudio\n          ref=\"positionalAudioRef\"\n          :ready\n          :inner-angle=\"innerAngle.value\"\n          :outer-angle=\"outerAngle.value\"\n          :outer-gain=\"outerGain.value\"\n          :helper=\"helper.value\"\n          url=\"https://raw.githubusercontent.com/Tresjs/assets/main/music/ping-pong.mp3\"\n        />\n      </Suspense>\n    </Sphere>\n    <primitive\n      v-if=\"state?.scene\"\n      :scale=\"[.2, .2, .2]\"\n      :position=\"[0, -1.15, 0]\"\n      receive-shadow\n      :object=\"state?.scene\"\n    />\n    <TresAmbientLight\n      color=\"#ffffff\"\n      :intensity=\"2\"\n    />\n    <TresDirectionalLight\n      :position=\"[5, 10, 0]\"\n      :intensity=\"2\"\n      cast-shadow\n    />\n  </TresCanvas>\n</template>\n\n<style scoped>\n.ready {\n  width: 100%;\n  height: 100%;\n  position: absolute;\n  z-index: 24;\n  background-color: rgba(0, 0, 0, 0.75);\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  backdrop-filter: blur(5px);\n}\n\n.controls {\n  position: absolute;\n  z-index: 1;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  backdrop-filter: blur(5px);\n  top: 25px;\n  left: 25px;\n  column-gap: 5px;\n}\n\n.ready button,\n.controls button {\n  padding: 5px 10px;\n  background: #1b1c1e;\n  border: 1px solid #161618;\n}\n</style>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/PrecipitationBeamDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { Precipitation } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\n</script>\n\n<template>\n  <TresCanvas clear-color=\"#333\">\n    <TresPerspectiveCamera :position=\"[0, 2, 15]\" />\n    <Precipitation\n      :position=\"[0, 3, 7.5]\"\n      :randomness=\"0\"\n      :speed=\"0.5\"\n      :count=\"2000\"\n      :area=\"[1, 10, 1]\"\n    />\n    <TresGridHelper :args=\"[10, 10]\" />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/PrecipitationDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { Precipitation } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\n</script>\n\n<template>\n  <TresCanvas clear-color=\"#333\">\n    <TresPerspectiveCamera :position=\"[0, 2, 15]\" />\n    <Precipitation />\n    <TresGridHelper :args=\"[10, 10]\" />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/PrecipitationRainDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { Precipitation } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\n</script>\n\n<template>\n  <TresCanvas clear-color=\"#333\">\n    <TresPerspectiveCamera :position=\"[0, 2, 15]\" />\n    <Precipitation\n      :randomness=\"0\"\n      :speed=\"1\"\n      :count=\"2500\"\n    />\n    <TresGridHelper :args=\"[10, 10]\" />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/PrecipitationStormDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { Precipitation } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\n</script>\n\n<template>\n  <TresCanvas clear-color=\"#333\">\n    <TresPerspectiveCamera :position=\"[0, 2, 15]\" />\n    <Precipitation\n      :randomness=\"3\"\n      :speed=\"1\"\n      :count=\"2500\"\n    />\n    <TresGridHelper :args=\"[10, 10]\" />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/QuadraticBezierLineDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { OrbitControls, QuadraticBezierLine } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\n</script>\n\n<template>\n  <TresLeches />\n  <TresCanvas clear-color=\"#4f4f4f\">\n    <QuadraticBezierLine\n      :start=\"[-1, 0, 0]\"\n      :end=\"[1, 2, 0]\"\n      :line-width=\"10\"\n      color=\"#fbb03b\"\n    />\n    <TresGridHelper />\n    <OrbitControls />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/ReflectorDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport {\n  MeshWobbleMaterial,\n  OrbitControls,\n  Reflector,\n  Stars,\n} from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\n</script>\n\n<template>\n  <TresCanvas clear-color=\"#111\">\n    <TresPerspectiveCamera\n      :position=\"[3, 2, 6]\"\n      :look-at=\"[0, 0, 0]\"\n    />\n    <Stars />\n    <TresMesh>\n      <TresTorusGeometry />\n      <MeshWobbleMaterial\n        color=\"orange\"\n        :speed=\"1\"\n        :factor=\"2\"\n      />\n    </TresMesh>\n    <Reflector\n      :rotation=\"[-Math.PI * 0.5, 0, 0]\"\n      :position=\"[0, -2, 0]\"\n      color=\"#f7f7f7\"\n    >\n      <TresCircleGeometry :args=\"[10, 32]\" />\n    </Reflector>\n    <TresAmbientLight :intensity=\"1\" />\n    <OrbitControls />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/RoundedBoxDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { Html, OrbitControls, RoundedBox } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\n</script>\n\n<template>\n  <TresCanvas\n    clear-color=\"#111\"\n  >\n    <TresPerspectiveCamera\n      :position=\"[0, 0, 7]\"\n      :fov=\"45\"\n      :aspect=\"1\"\n      :near=\"0.1\"\n      :far=\"1000\"\n    />\n    <OrbitControls />\n    <RoundedBox\n      :position-x=\"3\"\n      :args=\"[1, 1, 1, 2, 1]\"\n    >\n      <TresMeshBasicMaterial\n        :color=\"0x00FF00\"\n        wireframe\n      />\n      <Html\n        center\n        transform\n        :distance-factor=\"4\"\n        :position=\"[0, 1, 0.65]\"\n        :scale=\"[0.75, 0.75, 0.75]\"\n      >\n        <h1 class=\"bg-white dark:bg-dark text-xs p-1 rounded\">\n          I can be a quadsphere too\n        </h1>\n      </Html>\n    </RoundedBox>\n    <RoundedBox\n      :position-x=\"-3\"\n    >\n      <TresMeshBasicMaterial\n        :color=\"0x00FF00\"\n        wireframe\n      />\n      <Html\n        center\n        transform\n        :distance-factor=\"4\"\n        :position=\"[0, 1, 0.65]\"\n        :scale=\"[0.75, 0.75, 0.75]\"\n      >\n        <h1 class=\"bg-white dark:bg-dark text-xs p-1 rounded\">\n          I have wireframe active\n        </h1>\n      </Html>\n    </RoundedBox>\n    <RoundedBox />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/SVGDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { OrbitControls, UseSVG } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\n\nconst svgURL = 'https://raw.githubusercontent.com/'\n  + 'Tresjs/assets/main/svgs/cientos_heart.svg'\n</script>\n\n<template>\n  <TresCanvas clear-color=\"#333\">\n    <OrbitControls />\n    <Suspense>\n      <UseSVG\n        :src=\"svgURL\"\n        :position=\"[-0.4, 1, 0]\"\n        :scale=\"0.01\"\n      />\n    </Suspense>\n    <TresGridHelper />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/SamplerDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { OrbitControls, Sampler } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\n</script>\n\n<template>\n  <TresCanvas clear-color=\"#82DBC5\">\n    <TresPerspectiveCamera :position=\"[0, 0.5, 5]\" />\n    <OrbitControls />\n\n    <Sampler :count=\"50\">\n      <TresMesh>\n        <TresTorusGeometry />\n      </TresMesh>\n\n      <TresInstancedMesh :args=\"[null!, null!, 1000]\">\n        <TresBoxGeometry :args=\"[0.1, 0.1, 0.1]\" />\n        <TresMeshNormalMaterial />\n      </TresInstancedMesh>\n    </Sampler>\n    <TresGridHelper :args=\"[10, 10]\" />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/ScreenQuadDemo.vue",
    "content": "<script setup>\nimport { TresCanvas } from '@tresjs/core'\nimport { ScreenQuad } from '@tresjs/cientos'\n</script>\n\n<template>\n  <TresCanvas>\n    <TresOrthographicCamera :args=\"[-1, 1, 1, -1, 0, 1000]\" :position=\"[0, 0, 1]\" :manual=\"true\" />\n    <ScreenQuad>\n      <TresMeshBasicMaterial color=\"red\" />\n    </ScreenQuad>\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/ScreenSizerDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { TresCanvas } from '@tresjs/core'\nimport { OrbitControls, ScreenSizer } from '@tresjs/cientos'\n</script>\n\n<template>\n  <TresCanvas clear-color=\"#3f3f3f\">\n    <TresPerspectiveCamera :position=\"[10, 10, 10]\" />\n    <OrbitControls />\n    <ScreenSizer>\n      <TresMesh>\n        <TresBoxGeometry :args=\"[100, 100, 100]\" />\n        <TresMeshNormalMaterial />\n      </TresMesh>\n    </ScreenSizer>\n    <TresMesh :position-x=\"5\">\n      <TresBoxGeometry />\n      <TresMeshNormalMaterial />\n    </TresMesh>\n    <TresGridHelper :args=\"[10, 10]\" />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/ScreenSpaceDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { OrbitControls, ScreenSpace } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\n</script>\n\n<template>\n  <TresCanvas clear-color=\"#333\">\n    <TresPerspectiveCamera />\n    <OrbitControls />\n    <ScreenSpace :depth=\"5\">\n      <TresMesh>\n        <TresTorusGeometry />\n        <TresMeshNormalMaterial />\n      </TresMesh>\n    </ScreenSpace>\n    <TresGridHelper :args=\"[10, 10]\" />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/ScrollControlsDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { Box, ScrollControls, Stars } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { useControls } from '@tresjs/leches'\nimport { ref } from 'vue'\nimport '@tresjs/leches/styles'\n\nconst boxRef = ref()\nconst progress = ref(0)\n\nuseControls('fpsgraph')\nuseControls({\n  progress: progress.value,\n})\n\nfunction onLoop() {\n  if (boxRef.value) {\n    boxRef.value.instance.rotation.x = progress.value * 10\n    boxRef.value.instance.rotation.y = progress.value * 2\n  }\n}\n</script>\n\n<template>\n  <TresCanvas\n    class=\"important-absolute\"\n    clear-color=\"#333\"\n    @loop=\"onLoop\"\n  >\n    <TresPerspectiveCamera :position=\"[0, 2, 5]\" />\n    <Stars :radius=\"1\" />\n    <TresGridHelper :args=\"[10, 10]\" />\n    <ScrollControls />\n    <Box\n      :scale=\"0.5\"\n      :color=\"0xFF00FF\"\n      :position=\"[-1, 1, 0]\"\n    />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/ScrollControlsHorizontalDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { Box, ScrollControls, Stars } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\n</script>\n\n<template>\n  <TresCanvas\n    class=\"important-absolute\"\n    clear-color=\"#333\"\n  >\n    <TresPerspectiveCamera :position=\"[0, 2, 5]\" />\n    <Stars :radius=\"1\" />\n    <TresGridHelper :args=\"[10, 10]\" />\n    <ScrollControls horizontal />\n    <Box\n      :scale=\"0.5\"\n      :color=\"0xFF00FF\"\n      :position=\"[-1, 1, 0]\"\n    />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/ScrollControlsPagesDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { Box, ScrollControls, Stars } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\n</script>\n\n<template>\n  <TresCanvas\n    class=\"important-absolute\"\n    clear-color=\"#333\"\n  >\n    <TresPerspectiveCamera :position=\"[0, 2, 5]\" />\n    <Stars :radius=\"1\" />\n    <TresGridHelper :args=\"[10, 10]\" />\n    <ScrollControls\n      :pages=\"20\"\n      :distance=\"20\"\n      :smooth-scroll=\"0.05\"\n    />\n    <Box\n      :scale=\"0.5\"\n      :color=\"0xFF00FF\"\n      :position=\"[-1, 1, 0]\"\n    />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/ScrollControlsProgressCameraDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { Box, ScrollControls, Stars } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { ref } from 'vue'\n\nconst boxRef = ref()\nconst progress = ref(0)\n\nfunction onLoop() {\n  if (boxRef.value) {\n    boxRef.value.instance.rotation.x = progress.value * 10\n    boxRef.value.instance.rotation.y = progress.value * 2\n    boxRef.value.instance.position.x = progress.value * 4.5\n  }\n}\n</script>\n\n<template>\n  <TresCanvas\n    class=\"important-absolute\"\n    clear-color=\"#333\"\n    @loop=\"onLoop\"\n  >\n    <TresPerspectiveCamera :position=\"[0, 2, 5]\" />\n    <Stars :radius=\"1\" />\n    <TresGridHelper :args=\"[10, 10]\" />\n    <ScrollControls\n      v-model=\"progress\"\n      :distance=\"0\"\n    />\n    <Box\n      ref=\"boxRef\"\n      :scale=\"0.5\"\n      :color=\"0xFF00FF\"\n      :position=\"[-1, 1, 0]\"\n    />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/ScrollControlsProgressDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { Box, ScrollControls, Stars } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { ref } from 'vue'\n\nconst boxRef = ref()\nconst progress = ref(0)\n\nfunction onLoop() {\n  if (boxRef.value) {\n    boxRef.value.instance.rotation.x = progress.value * 10\n    boxRef.value.instance.rotation.y = progress.value * 2\n    boxRef.value.instance.position.x = progress.value * 4.5\n  }\n}\n</script>\n\n<template>\n  <TresCanvas\n    class=\"important-absolute\"\n    clear-color=\"#333\"\n    @loop=\"onLoop\"\n  >\n    <TresPerspectiveCamera :position=\"[0, 2, 5]\" />\n    <Stars :radius=\"1\" />\n    <TresGridHelper :args=\"[10, 10]\" />\n    <ScrollControls\n      v-model=\"progress\"\n      :distance=\"2\"\n    />\n    <Box\n      ref=\"boxRef\"\n      :scale=\"0.5\"\n      :color=\"0xFF00FF\"\n      :position=\"[-1, 1, 0]\"\n    />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/ScrollControlsSlotsDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { Box, ScrollControls, Sphere, Stars } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { ref } from 'vue'\n\nconst scRef = ref()\nconst boxRef = ref()\nconst progress = ref(0)\n\nfunction onLoop() {\n  if (boxRef.value) {\n    boxRef.value.instance.rotation.x = progress.value * 10\n    boxRef.value.instance.rotation.y = progress.value * 2\n  }\n}\n</script>\n\n<template>\n  <TresCanvas\n    clear-color=\"#333\"\n    class=\"important-absolute\"\n    @loop=\"onLoop\"\n  >\n    <TresPerspectiveCamera :position=\"[0, 2, 5]\" />\n    <Stars :radius=\"1\" />\n    <TresGridHelper :args=\"[10, 10]\" />\n    <Sphere\n      :scale=\"0.1\"\n      :position=\"[1, 2, 0]\"\n    />\n    <ScrollControls\n      ref=\"scRef\"\n      v-model=\"progress\"\n      :distance=\"20\"\n      :smooth-scroll=\"0.1\"\n    >\n      <Box\n        ref=\"boxRef\"\n        :scale=\"0.5\"\n        :color=\"0xFF00FF\"\n        :position=\"[-1, 1, 0]\"\n      />\n    </ScrollControls>\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/SkyDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { OrbitControls, Sky } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\n</script>\n\n<template>\n  <TresCanvas :tone-mapping-exposure=\"0.25\">\n    <TresPerspectiveCamera :position=\"[0, 0, 2000]\" />\n    <Sky />\n    <OrbitControls\n      :enable-pan=\"false\"\n      :enable-zoom=\"false\"\n    />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/SmokeDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { Box, OrbitControls, Smoke } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { NoToneMapping, SRGBColorSpace } from 'three'\n\nconst gl = {\n  clearColor: '#333',\n  alpha: true,\n  outputColorSpace: SRGBColorSpace,\n  toneMapping: NoToneMapping,\n}\n</script>\n\n<template>\n  <TresCanvas\n    v-bind=\"gl\"\n  >\n    <TresPerspectiveCamera :position=\"[0, 2, 5]\" />\n    <Suspense>\n      <Smoke\n        :segments=\"4\"\n        :width=\"1\"\n        :position=\"[-4, -2, 0]\"\n      />\n    </Suspense>\n    <Suspense>\n      <Smoke\n        :segments=\"4\"\n        :width=\"1\"\n        :position=\"[-4, 2, 0]\"\n      />\n    </Suspense>\n    <Suspense>\n      <Smoke\n        :segments=\"4\"\n        :width=\"1\"\n      />\n    </Suspense>\n    <Suspense>\n      <Smoke\n        :segments=\"4\"\n        :width=\"1\"\n        :position=\"[4, -2, 0]\"\n      />\n    </Suspense>\n    <Suspense>\n      <Smoke\n        :segments=\"4\"\n        :width=\"1\"\n        :position=\"[4, 2, 0]\"\n      />\n    </Suspense>\n    <Box :args=\"[2, 2]\">\n      <TresMeshToonMaterial color=\"#82DBC5\" />\n    </Box>\n    <TresGridHelper :args=\"[10, 10]\" />\n    <TresAmbientLight :intensity=\"1\" />\n    <TresDirectionalLight\n      :intensity=\"1\"\n      :position=\"[2, 2, 2]\"\n    />\n    <OrbitControls />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/SoftShadowsDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { TresCanvas } from '@tresjs/core'\nimport { OrbitControls, SoftShadows } from '@tresjs/cientos'\nimport { Group, MeshPhongMaterial, SphereGeometry, Vector3 } from 'three'\nimport { onMounted, onUnmounted, shallowRef } from 'vue'\n\nconst sphereGeo = new SphereGeometry(0.3, 20, 20)\nconst sphereMat = new MeshPhongMaterial({ color: '#82dbc5' })\nconst spherePositions = Array.from({ length: 9 }).fill(null).map(() => new Vector3())\nlet ii = 0\nfor (const p of spherePositions) {\n  p.x = ii * 0.5 - 2\n  ii++\n}\n\nconst spheres = shallowRef(new Group())\nlet intervalId: ReturnType<typeof setInterval>\nlet elapsed = 0\nonMounted(() => {\n  intervalId = setInterval(() => {\n    let ii = 0\n    elapsed += 1000 / 30\n    for (const sphere of spheres.value.children) {\n      ii += 0.2\n      sphere.position.y = Math.sin(ii + elapsed * 0.001) ** 2 * 3 + 0.5\n    }\n  }, 1000 / 30)\n})\n\nonUnmounted(() => {\n  clearInterval(intervalId)\n})\n</script>\n\n<template>\n  <TresCanvas :shadows=\"true\" :shadowMap-enabled=\"true\">\n    <TresFog :args=\"['#FFFFFF', 5, 100]\" />\n\n    <OrbitControls />\n    <TresPerspectiveCamera :position=\"[0, 7, -5]\" :fov=\"60\" />\n\n    <TresAmbientLight color=\"#AAAAAA\" :intensity=\"2\" />\n    <TresDirectionalLight\n      color=\"#F0F6FF\"\n      :intensity=\"6\"\n      :position=\"[2, 8, 4]\"\n      :cast-shadow=\"true\"\n      :shadow-mapSize-width=\"1024\"\n      :shadow-mapSize-height=\"1024\"\n      :shadow-camera-far=\"20\"\n    />\n\n    <SoftShadows />\n\n    <TresMesh :position=\"[0, 1.5, 1]\" :scale-y=\"3\" :cast-shadow=\"true\" :receive-shadow=\"true\" name=\"column\">\n      <TresBoxGeometry />\n      <TresMeshPhongMaterial color=\"#4f4f4f\" />\n    </TresMesh>\n\n    <TresMesh :rotation-x=\"-Math.PI / 2\" :receive-shadow=\"true\" name=\"ground\">\n      <TresPlaneGeometry :args=\"[100, 100, 8, 8]\" />\n      <TresMeshPhongMaterial color=\"#fbb03b\" />\n    </TresMesh>\n\n    <TresGroup ref=\"spheres\" name=\"spheres\">\n      <TresMesh\n        v-for=\"p, i of spherePositions\"\n        :key=\"i\"\n        :material=\"sphereMat\"\n        :geometry=\"sphereGeo\"\n        :position=\"p\"\n        :cast-shadow=\"true\"\n        :receive-shadow=\"true\"\n      />\n    </TresGroup>\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/SparklesDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { OrbitControls, Sparkles, TorusKnot } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\n</script>\n\n<template>\n  <TresCanvas clear-color=\"#333\">\n    <TresPerspectiveCamera :position=\"[0, 0, 5]\" />\n    <TorusKnot :args=\"[1, 0.25, 128, 16]\">\n      <TresMeshBasicMaterial color=\"#222\" />\n      <Sparkles />\n    </TorusKnot>\n    <OrbitControls />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/SparklesDirectionalLightDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { OrbitControls, Sparkles, Sphere, Torus } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { shallowRef } from 'vue'\n\nconst lightRef = shallowRef()\n\nfunction onLoop({ elapsed }: { elapsed: number }) {\n  if (lightRef.value) {\n    lightRef.value.position.x = Math.cos(elapsed) * 2.5\n    lightRef.value.position.y = Math.sin(elapsed) * 2.5\n  }\n}\n</script>\n\n<template>\n  <TresCanvas\n    clear-color=\"#333\"\n    @loop=\"onLoop\"\n  >\n    <TresPerspectiveCamera :position=\"[0, 0, 8]\" />\n    <TresDirectionalLight ref=\"lightRef\">\n      <Sphere\n        color=\"white\"\n        :scale=\"0.1\"\n      />\n    </TresDirectionalLight>\n    <Torus :args=\"[1, 0.25, 16, 48]\">\n      <TresMeshBasicMaterial color=\"#222\" />\n      <Sparkles :directional-light=\"lightRef\" />\n    </Torus>\n    <OrbitControls />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/SparklesMixDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { Sparkles, Sphere } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { TresLeches, useControls } from '@tresjs/leches'\nimport { shallowRef } from 'vue'\nimport '@tresjs/leches/styles'\n\nconst lightRef = shallowRef()\nconst { value: mix } = useControls({\n  mix: { value: 0, min: 0, max: 1, step: 0.01 },\n})\n\nfunction onLoop({ elapsed }: { elapsed: number }) {\n  if (lightRef.value) {\n    lightRef.value.position.x = Math.cos(elapsed) * 3\n    lightRef.value.position.y = Math.sin(elapsed) * 3\n  }\n}\n</script>\n\n<template>\n  <TresLeches class=\"top-0 important-left-4\" />\n  <TresCanvas\n    clear-color=\"#333\"\n    @loop=\"onLoop\"\n  >\n    <TresPerspectiveCamera :position=\"[-2.5, 0, 8]\" />\n    <TresDirectionalLight ref=\"lightRef\">\n      <Sphere\n        color=\"white\"\n        :scale=\"0.1\"\n      />\n    </TresDirectionalLight>\n    <Sphere :args=\"[1, 16, 16]\">\n      <TresMeshBasicMaterial color=\"#222\" />\n      <Sparkles\n        :directional-light=\"lightRef\"\n        :mix-alpha=\"mix\"\n        :mix-color=\"mix\"\n        :mix-offset=\"mix\"\n        :mix-size=\"mix\"\n        :mix-surface-distance=\"mix\"\n        :lifetime-sec=\"2\"\n        :sequence-alpha=\"[0.1, 1.0]\"\n        :sequence-surface-distance=\"[0.1, 0.5]\"\n      />\n    </Sphere>\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/SparklesSequenceDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { OrbitControls, Sparkles, Sphere } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\n</script>\n\n<template>\n  <TresCanvas clear-color=\"#333\">\n    <TresPerspectiveCamera :position=\"[0, 0, 8]\" />\n    <Sphere>\n      <TresMeshBasicMaterial color=\"#222\" />\n      <Sparkles\n        :sequence-alpha=\"[[0., 0.], [0.6, 1.0], [0.7, 0.0], [1.0, 1.0]]\"\n        :sequence-color=\"['yellow', 'white', 'orange', 'red', 'black']\"\n        :sequence-offset=\"[[0.7, [0, 0, 0]], [0.75, [0, 0.1, 0]], [1.0, [0, 0.5, 0]]]\"\n        :sequence-size=\"[[0.0, 0.0], [0.7, 1.0]]\"\n        :sequence-surface-distance=\"[[0.0, 0.0], [0.7, 1.0]]\"\n        :lifetime-sec=\"2.0\"\n        :size=\"2\"\n        :surface-distance=\"0.8\"\n        :mix-color=\"1.0\"\n      />\n    </Sphere>\n    <OrbitControls />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/StageDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { OrbitControls, Stage } from '@tresjs/cientos'\nimport { type LoaderProto, TresCanvas, useLoader } from '@tresjs/core'\nimport type { Mesh, Object3D } from 'three'\nimport { type GLTF, GLTFLoader } from 'three-stdlib'\n\nconst scene = await useLoader(GLTFLoader as LoaderProto<GLTF>, 'https://raw.githubusercontent.com/Tresjs/assets/215208b4a54736965d525ab9c47d82dbfe4b2a02/models/gltf/suzanne/suzanne.glb') as unknown as { nodes: { Suzanne: Object3D } }\nconst suzanne = scene.nodes.Suzanne as Mesh\n</script>\n\n<template>\n  <TresCanvas clear-color=\"#82DBC5\">\n    <TresPerspectiveCamera :position=\"[0, 5, 15]\" />\n    <OrbitControls make-default />\n    <Stage\n      :adjust-camera=\"0.05\"\n      :shadows=\"{ type: 'contact', color: '#012' }\"\n      :align=\"{ top: true, disableX: true }\"\n      :rotation-y=\"0.5\"\n    >\n      <Suspense>\n        <primitive\n          :object=\"suzanne\"\n          :rotation=\"[5.6548, Math.PI, 0]\"\n          :position=\"[0, 0.90, 1]\"\n        >\n          <TresMeshStandardMaterial color=\"#fbb03b\" :metalness=\"1\" :roughness=\"0\" />\n        </primitive>\n      </Suspense>\n\n      <TresMesh\n        :position=\"[-1.75, 0.25, 1.25]\"\n        :scale=\"0.5\"\n      >\n        <TresBoxGeometry />\n        <TresMeshStandardMaterial color=\"#4f4f4f\" />\n      </TresMesh>\n\n      <TresMesh :position=\"[-1.65, 1, -1.5]\">\n        <TresSphereGeometry />\n        <TresMeshStandardMaterial color=\"#82dbc5\" />\n      </TresMesh>\n    </Stage>\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/StarsDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { OrbitControls, Stars } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { shallowRef } from 'vue'\n\nconst yRotation = shallowRef(0)\n\nfunction onLoop({ delta }: { delta: number }) {\n  yRotation.value += 0.02 * delta\n}\n</script>\n\n<template>\n  <TresCanvas\n    clear-color=\"#333\"\n    @loop=\"onLoop\"\n  >\n    <TresPerspectiveCamera :position=\"[0, 2, 5]\" />\n    <Stars\n      :rotation=\"[0, yRotation, 0]\"\n      :radius=\"50\"\n      :depth=\"50\"\n      :count=\"5000\"\n      :size=\"0.3\"\n      :size-attenuation=\"true\"\n    />\n    <TresGridHelper :args=\"[4, 4]\" />\n    <OrbitControls />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/SuperformulaDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { OrbitControls, Superformula } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\n</script>\n\n<template>\n  <TresCanvas clear-color=\"#777\">\n    <Superformula\n      :num-arms-b=\"24\"\n      :exp-b=\"[40, 30, 20]\"\n    >\n      <TresMeshNormalMaterial />\n    </Superformula>\n    <OrbitControls />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/SuperformulaLechesDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { Superformula } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { TresLeches, useControls } from '@tresjs/leches'\nimport { AmbientLight, DirectionalLight, MeshPhongMaterial } from 'three'\nimport '@tresjs/leches/styles'\n\nconst { numArmsA, numArmsB, expA1 } = useControls({\n  numArmsA: { value: 1, min: 1, max: 40, step: 1 },\n  numArmsB: { value: 1, min: 1, max: 40, step: 0.1 },\n  expA1: { value: 8, min: 4, max: 40, step: 0.01 },\n})\n\nconst material = new MeshPhongMaterial({ color: '#fbb03b', shininess: 1000 })\nconst directionalLight = new DirectionalLight('white', 4)\ndirectionalLight.position.set(1, 1, 1)\nconst ambientLight = new AmbientLight('pink', 1)\n</script>\n\n<template>\n  <TresLeches class=\"important-top-4 important-left-4\" />\n  <TresCanvas clear-color=\"#777\">\n    <primitive :object=\"directionalLight\" />\n    <primitive :object=\"ambientLight\" />\n    <Superformula\n      :position=\"[1.5, 0.7, 0]\"\n      :width-segments=\"128\"\n      :height-segments=\"128\"\n      :num-arms-a=\"numArmsA.value\"\n      :num-arms-b=\"numArmsB.value\"\n      :exp-a=\"[expA1.value, 8, 0]\"\n      :exp-b=\"[2, 1, 2]\"\n      color=\"orange\"\n    >\n      <primitive :object=\"material\" />\n    </Superformula>\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/Text3Demo.vue",
    "content": "<script setup lang=\"ts\">\nimport { OrbitControls, Text3D } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { BasicShadowMap, NoToneMapping, SRGBColorSpace } from 'three'\nimport { ref } from 'vue'\n\nconst gl = {\n  clearColor: '#82DBC5',\n  shadows: true,\n  alpha: false,\n  shadowMapType: BasicShadowMap,\n  outputColorSpace: SRGBColorSpace,\n  toneMapping: NoToneMapping,\n}\n\nconst fontPath = 'https://raw.githubusercontent.com/Tresjs/assets/main/fonts/FiraCodeRegular.json'\n\nconst reactiveText = ref('You can edit me...')\n</script>\n\n<template>\n  <div class=\"bg-gray-100 flex justify-center\">\n    <input\n      v-model=\"reactiveText\"\n      class=\"p-2 m-2 rounded-md bg-white border border-gray-400 color-red\"\n    />\n  </div>\n  <TresCanvas v-bind=\"gl\">\n    <TresPerspectiveCamera :position=\"[0, 0.5, 5]\" />\n    <OrbitControls />\n    <Suspense>\n      <Text3D\n        :text=\"reactiveText\"\n        :size=\"0.3\"\n        :font=\"fontPath\"\n        center\n        :need-updates=\"true\"\n      >\n        <TresMeshNormalMaterial />\n      </Text3D>\n    </Suspense>\n    <TresAmbientLight :intensity=\"1\" />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/TransformControlsDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { OrbitControls, TransformControls } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\n\nimport { TresLeches, useControls } from '@tresjs/leches'\nimport { BasicShadowMap, NoToneMapping, SRGBColorSpace } from 'three'\nimport { ref, shallowReactive } from 'vue'\nimport '@tresjs/leches/styles'\n\nconst gl = {\n  clearColor: '#201919',\n  shadows: true,\n  alpha: false,\n  shadowMapType: BasicShadowMap,\n  outputColorSpace: SRGBColorSpace,\n  toneMapping: NoToneMapping,\n}\n\nconst boxRef = ref()\nconst transformState = shallowReactive({\n  showX: true,\n  showY: true,\n  showZ: true,\n})\n\nconst { value: mode } = useControls({\n  mode: {\n    value: 'translate',\n    options: [{\n      text: 'Translate',\n      value: 'translate',\n    }, {\n      text: 'Rotate',\n      value: 'rotate',\n    }, {\n      text: 'Scale',\n      value: 'scale',\n    }],\n  },\n})\n</script>\n\n<template>\n  <TresLeches class=\"top-0 important-left-4\" />\n  <TresCanvas\n    v-bind=\"gl\"\n  >\n    <TresPerspectiveCamera\n      :position=\"[11, 11, 11]\"\n      :fov=\"45\"\n      :near=\"0.1\"\n      :far=\"1000\"\n      :look-at=\"[-8, 3, -3]\"\n    />\n    <OrbitControls make-default />\n    <TransformControls\n      :object=\"boxRef\"\n      v-bind=\"transformState\"\n      :mode=\"mode\"\n    />\n    <TresMesh\n      ref=\"boxRef\"\n      :position=\"[0, 4, 0]\"\n      cast-shadow\n    >\n      <TresBoxGeometry :args=\"[1.5, 1.5, 1.5]\" />\n      <TresMeshToonMaterial color=\"#FBB03B\" />\n    </TresMesh>\n    <TresMesh\n      :rotation=\"[-Math.PI / 2, 0, 0]\"\n      receive-shadow\n    >\n      <TresPlaneGeometry :args=\"[10, 10, 10, 10]\" />\n      <TresMeshToonMaterial />\n    </TresMesh>\n    <TresAmbientLight :intensity=\"0.5\" />\n    <TresDirectionalLight\n      :position=\"[0, 8, 4]\"\n      :intensity=\"1.5\"\n      cast-shadow\n    />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/UseFBODemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { OrbitControls } from '@tresjs/cientos'\nimport type { TresObject } from '@tresjs/core'\nimport { TresCanvas } from '@tresjs/core'\nimport { ACESFilmicToneMapping, SRGBColorSpace } from 'three'\nimport { shallowRef } from 'vue'\n\nconst gl = {\n  clearColor: '#82DBC5',\n  shadows: true,\n  alpha: false,\n  outputColorSpace: SRGBColorSpace,\n  toneMapping: ACESFilmicToneMapping,\n}\n\nconst torusRef = shallowRef<TresObject | null>(null)\nconst capsuleRef = shallowRef<TresObject | null>(null)\n\nfunction onLoop({ elapsed }: { elapsed: number }) {\n  if (!torusRef.value || !capsuleRef.value) { return }\n\n  torusRef.value.rotation.x = elapsed * 0.745\n  torusRef.value.rotation.y = elapsed * 0.361\n\n  capsuleRef.value.rotation.x = elapsed * 0.471\n  capsuleRef.value.rotation.z = elapsed * 0.632\n}\n</script>\n\n<template>\n  <TresCanvas\n    v-bind=\"gl\"\n    @loop=\"onLoop\"\n  >\n    <TresPerspectiveCamera :position=\"[0, 0.5, 5]\" />\n    <OrbitControls />\n\n    <TresGridHelper :args=\"[10, 10]\" />\n\n    <FboCube />\n\n    <TresMesh\n      ref=\"torusRef\"\n      :position=\"[3, 0, 0]\"\n    >\n      <TresTorusGeometry :args=\"[1, 0.5, 16, 100]\" />\n      <TresMeshNormalMaterial />\n    </TresMesh>\n\n    <TresMesh\n      ref=\"capsuleRef\"\n      :position=\"[-2, 0, 0]\"\n    >\n      <TresCapsuleGeometry :args=\"[0.4, 1, 4, 8]\" />\n      <TresMeshNormalMaterial />\n    </TresMesh>\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/UseFBXDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { OrbitControls, useFBX } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { BasicShadowMap, Mesh, NoToneMapping, SRGBColorSpace } from 'three'\nimport { watchEffect } from 'vue'\n\nconst gl = {\n  clearColor: '#82DBC5',\n  shadows: true,\n  alpha: false,\n  shadowMapType: BasicShadowMap,\n  outputColorSpace: SRGBColorSpace,\n  toneMapping: NoToneMapping,\n}\n\nconst path = 'https://raw.githubusercontent.com/'\n  + 'Tresjs/assets/main/models/fbx/low-poly-truck/Jeep_done.fbx'\n\n// Use the new reactive useFBX API\nconst { state: model } = useFBX(path)\n\n// Apply transformations and shadows when model loads\nwatchEffect(() => {\n  if (model.value) {\n    model.value.scale.set(0.01, 0.01, 0.01)\n    model.value.position.set(0, -1.6, 0)\n    model.value.rotation.y = -Math.PI * 0.5\n\n    // Enable shadows for all meshes\n    model.value.traverse((child) => {\n      if (child instanceof Mesh) {\n        child.castShadow = true\n      }\n    })\n  }\n})\n</script>\n\n<template>\n  <TresCanvas v-bind=\"gl\">\n    <TresPerspectiveCamera :position=\"[5.3, 2.45, 9.3]\" :look-at=\"[0, 0, 0]\" />\n    <OrbitControls />\n    <primitive v-if=\"model\" :object=\"model\" />\n    <TresMesh\n      :rotate-x=\"Math.PI * -0.5\"\n      :position-y=\"-2\"\n      receive-shadow\n    >\n      <TresPlaneGeometry :args=\"[40, 40]\" />\n      <TresMeshStandardMaterial :color=\"0xF7F7F7\" />\n    </TresMesh>\n    <TresAmbientLight :intensity=\"1\" />\n    <TresDirectionalLight\n      :intensity=\"1\"\n      cast-shadow\n      :position=\"[5, 10, 5]\"\n    />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/UseGLTFDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { OrbitControls, useGLTF } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\n\nconst path = 'https://raw.githubusercontent.com/'\n  + 'Tresjs/assets/main/models/gltf/blender-cube.glb'\nconst { state } = useGLTF(path)\n</script>\n\n<template>\n  <TresCanvas clear-color=\"#FBB03B\">\n    <TresPerspectiveCamera :position=\"[3, 2, 5]\" />\n    <OrbitControls />\n\n    <primitive v-if=\"state\" :object=\"state?.scene\" />\n\n    <TresDirectionalLight\n      :intensity=\"2\"\n      :position=\"[3, 3, 3]\"\n    />\n    <TresAmbientLight :intensity=\"1\" />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/UseSurfaceSamplerDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { OrbitControls, useSurfaceSampler } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { ref, watch } from 'vue'\n\nconst torusRef = ref()\nconst instancesRef = ref()\n\nwatch(torusRef, (value) => {\n  useSurfaceSampler(value, 50, instancesRef.value, 'color')\n})\n</script>\n\n<template>\n  <TresCanvas clear-color=\"#82DBC5\">\n    <TresPerspectiveCamera :position=\"[0, 0.5, 5]\" />\n    <OrbitControls />\n\n    <TresMesh ref=\"torusRef\">\n      <TresTorusGeometry />\n    </TresMesh>\n\n    <TresInstancedMesh\n      ref=\"instancesRef\"\n      :args=\"[null!, null!, 1_000]\"\n    >\n      <TresSphereGeometry :args=\"[0.1, 32, 32]\" />\n      <TresMeshNormalMaterial />\n    </TresInstancedMesh>\n\n    <TresGridHelper :args=\"[10, 10]\" />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/UseTextureDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { OrbitControls, useTexture } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\n\nconst path = 'https://raw.githubusercontent.com/Tresjs/assets/main/textures/black-rock/Rock035_2K_Color.jpg'\nconst { state: texture } = useTexture(path)\n</script>\n\n<template>\n  <TresCanvas clear-color=\"#FBB03B\">\n    <TresPerspectiveCamera :position=\"[3, 3, 3]\" />\n    <OrbitControls />\n    <TresMesh>\n      <TresSphereGeometry />\n      <TresMeshStandardMaterial :map=\"texture\" />\n    </TresMesh>\n    <TresAmbientLight :intensity=\"1\" />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/VideoTextureDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { OrbitControls, Sphere, useVideoTexture } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { ref } from 'vue'\n\nconst exampleVideo = 'https://raw.githubusercontent.com/'\n  + 'Tresjs/assets/main/textures/video-textures/useVideoTexture.mp4'\nconst texture = ref()\ntexture.value = await useVideoTexture(exampleVideo, { loop: false })\n</script>\n\n<template>\n  <TresCanvas clear-color=\"#333\">\n    <TresPerspectiveCamera\n      :position=\"[0, 5, 9]\"\n      :look-at=\"[0, 1, 0]\"\n    />\n    <OrbitControls />\n    <Sphere :position=\"[0, 2, 0]\">\n      <TresMeshBasicMaterial :map=\"texture\" />\n    </Sphere>\n    <TresGridHelper />\n    <TresAmbientLight />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/components/WobbleMaterialDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { MeshWobbleMaterial, OrbitControls } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\n</script>\n\n<template>\n  <TresCanvas clear-color=\"#82DBC5\">\n    <TresPerspectiveCamera :position=\"[3, 3, 3]\" />\n    <TresMesh>\n      <TresTorusGeometry />\n      <MeshWobbleMaterial\n        color=\"orange\"\n        :speed=\"1\"\n        :factor=\"2\"\n      />\n    </TresMesh>\n    <TresAmbientLight :intensity=\"1\" />\n    <TresDirectionalLight :position=\"[2, 2, 2]\" />\n    <OrbitControls />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/index.ts",
    "content": "// https://vitepress.dev/guide/custom-theme\nimport Theme from 'vitepress/theme'\nimport TresLayout from './TresLayout.vue'\nimport './style.css'\n\nimport 'uno.css'\n\nexport default {\n  ...Theme,\n  Layout: TresLayout,\n  enhanceApp(ctx) {\n    Theme.enhanceApp(ctx)\n    /* ctx.app.use(plausible) */\n  },\n}\n"
  },
  {
    "path": "docs/.vitepress/theme/style.css",
    "content": ":root {\n  --vp-home-hero-name-color: #82dbc5;\n  --vp-c-brand: #82dbc5;\n  --vp-c-dark: #1f1f1e;\n}\n\n/**\n * Component: Button\n * -------------------------------------------------------------------------- */\n\n:root {\n  --vp-button-brand-border: var(--vp-c-brand-light);\n  --vp-button-brand-text: var(--vp-c-text-dark-1);\n  --vp-button-brand-text: var(--vp-c-dark);\n  --vp-button-brand-bg: var(--vp-c-brand);\n  --vp-button-brand-hover-border: var(--vp-c-brand-light);\n  --vp-button-brand-hover-text: var(--vp-c-text-dark-1);\n  --vp-button-brand-hover-text: var(--vp-c-dark);\n  --vp-button-brand-hover-bg: var(--vp-c-brand-light);\n  --vp-button-brand-active-border: var(--vp-c-brand-light);\n  --vp-button-brand-active-text: var(--vp-c-text-dark-1);\n  --vp-button-brand-active-text: var(--vp-c-dark);\n  --vp-button-brand-active-bg: var(--vp-button-brand-bg);\n\n  --vp-button-alt-border: var(--vp-c-gray-light-3);\n  --vp-button-alt-text: var(--vp-c-text-light-1);\n  --vp-button-alt-bg: var(--vp-c-gray-light-5);\n  --vp-button-alt-hover-border: var(--vp-c-gray-light-3);\n  --vp-button-alt-hover-text: var(--vp-c-text-light-1);\n  --vp-button-alt-hover-bg: var(--vp-c-gray-light-4);\n  --vp-button-alt-active-border: var(--vp-c-gray-light-3);\n  --vp-button-alt-active-text: var(--vp-c-text-light-1);\n  --vp-button-alt-active-bg: var(--vp-c-gray-light-3);\n  --vp-button-alt-border: var(--vp-c-border);\n  --vp-button-alt-text: var(--vp-c-neutral);\n  --vp-button-alt-bg: var(--vp-c-mute);\n  --vp-button-alt-hover-border: var(--vp-c-border);\n  --vp-button-alt-hover-text: var(--vp-c-neutral);\n  --vp-button-alt-hover-bg: var(--vp-c-mute-dark);\n  --vp-button-alt-active-border: var(--vp-c-border);\n  --vp-button-alt-active-text: var(--vp-c-neutral);\n  --vp-button-alt-active-bg: var(--vp-c-mute-darker);\n\n  --vp-button-sponsor-border: var(--vp-c-gray-light-3);\n  --vp-button-sponsor-text: var(--vp-c-text-light-2);\n}\n\n.VPSidebar .link.active span {\n  font-weight: bold;\n}\n\n.vp-doc a {\n  text-decoration: dashed;\n  font-weight: bold;\n}\n\n.VPButton.medium.brand {\n  color: var(--vp-button-brand-text);\n}\n.VPButton.medium.alt {\n  border-color: var(--vp-button-alt-border);\n  color: var(--vp-button-alt-text);\n  background-color: var(--vp-button-alt-bg);\n}\n\n.demo-scene {\n  height: auto;\n  margin: 2rem 0;\n  overflow: hidden;\n  aspect-ratio: 16/9;\n  border-radius: 8px;\n}\n"
  },
  {
    "path": "docs/api-examples.md",
    "content": "---\noutline: deep\n---\n\n# Runtime API Examples\n\nThis page demonstrates usage of some of the runtime APIs provided by VitePress.\n\nThe main `useData()` API can be used to access site, theme, and page data for the current page. It works in both `.md` and `.vue` files:\n\n```md\n<script setup>\nimport { useData } from 'vitepress'\n\nconst { theme, page, frontmatter } = useData()\n</script>\n\n## Results\n\n### Theme Data\n<pre>{{ theme }}</pre>\n\n### Page Data\n<pre>{{ page }}</pre>\n\n### Page Frontmatter\n<pre>{{ frontmatter }}</pre>\n```\n\n<script setup>\nimport { useData } from 'vitepress'\n\nconst { site, theme, page, frontmatter } = useData()\n</script>\n\n## Results\n\n### Theme Data\n<pre>{{ theme }}</pre>\n\n### Page Data\n<pre>{{ page }}</pre>\n\n### Page Frontmatter\n<pre>{{ frontmatter }}</pre>\n\n## More\n\nCheck out the documentation for the [full list of runtime APIs](https://vitepress.dev/reference/runtime-api#usedata).\n"
  },
  {
    "path": "docs/component-list/components.ts",
    "content": "export default [\n  {\n    text: 'Abstractions',\n    items: [\n      { text: 'AnimatedSprite', link: '/guide/abstractions/animated-sprite' },\n      { text: 'Edges', link: '/guide/abstractions/edges' },\n      { text: 'Text3D', link: '/guide/abstractions/text-3d' },\n      { text: 'Levioso (Float)', link: '/guide/abstractions/levioso' },\n      { text: 'useAnimations', link: '/guide/abstractions/use-animations' },\n      { text: 'MouseParallax', link: '/guide/abstractions/mouse-parallax' },\n      { text: 'Lensflare', link: '/guide/abstractions/lensflare' },\n      { text: 'Reflector', link: '/guide/abstractions/reflector' },\n      { text: 'GlobalAudio', link: '/guide/abstractions/global-audio' },\n      { text: 'Fbo', link: '/guide/abstractions/fbo' },\n      { text: 'useFBO', link: '/guide/abstractions/use-fbo' },\n      {\n        text: 'useSurfaceSampler',\n        link: '/guide/abstractions/use-surface-sampler',\n      },\n      { text: 'Sampler', link: '/guide/abstractions/sampler' },\n      { text: 'PositionalAudio', link: '/guide/abstractions/positional-audio' },\n      { text: 'MarchingCubes', link: '/guide/abstractions/marching-cubes' },\n      { text: 'Mask', link: '/guide/abstractions/mask' },\n      { text: 'CubeCamera', link: '/guide/abstractions/cube-camera' },\n      { text: 'GradientTexture', link: '/guide/abstractions/gradient-texture' },\n      { text: 'ScreenSizer', link: '/guide/abstractions/screen-sizer' },\n      { text: 'ScreenSpace', link: '/guide/abstractions/screen-space' },\n      { text: 'Outline', link: '/guide/abstractions/outline' },\n      { text: 'Image', link: '/guide/abstractions/image' },\n      { text: 'Billboard', link: '/guide/abstractions/billboard' },\n    ],\n  },\n  {\n    text: 'Controls',\n    items: [\n      { text: 'OrbitControls', link: '/guide/controls/orbit-controls' },\n      { text: 'CameraControls', link: '/guide/controls/camera-controls' },\n      { text: 'TransformControls', link: '/guide/controls/transform-controls' },\n      {\n        text: 'PointerLockControls',\n        link: '/guide/controls/pointer-lock-controls',\n      },\n      { text: 'KeyboardControls', link: '/guide/controls/keyboard-controls' },\n      { text: 'ScrollControls', link: '/guide/controls/scroll-controls' },\n      { text: 'MapControls', link: '/guide/controls/map-controls' },\n      { text: 'Helper', link: '/guide/controls/helper' },\n    ],\n  },\n  {\n    text: 'Loaders',\n    items: [\n      { text: 'useProgress', link: '/guide/loaders/use-progress' },\n      { text: 'useGLTF', link: '/guide/loaders/use-gltf' },\n      { text: 'GLTFModel', link: '/guide/loaders/gltf-model' },\n      { text: 'useTexture', link: '/guide/loaders/use-texture' },\n      { text: 'useTextures', link: '/guide/loaders/use-textures' },\n      { text: 'useFBX', link: '/guide/loaders/use-fbx' },\n      { text: 'FBXModel', link: '/guide/loaders/fbx-model' },\n      { text: 'useVideoTexture', link: '/guide/loaders/use-video-texture' },\n      { text: 'useSVG', link: '/guide/loaders/use-svg' },\n    ],\n  },\n  {\n    text: 'Materials',\n    collapsed: true,\n    items: [\n      { text: 'MeshReflectionMaterial', link: '/guide/materials/mesh-reflection-material' },\n      { text: 'WobbleMaterial', link: '/guide/materials/wobble-material' },\n      { text: 'MeshGlassMaterial', link: '/guide/materials/glass-material' },\n      {\n        text: 'CustomShaderMaterial',\n        link: '/guide/materials/custom-shader-material',\n      },\n      {\n        text: 'HolographicMaterial',\n        link: '/guide/materials/holographic-material',\n      },\n      {\n        text: 'PointMaterial',\n        link: '/guide/materials/point-material',\n      },\n      {\n        text: 'MeshDiscardMaterial',\n        link: '/guide/materials/mesh-discard-material',\n      },\n    ],\n  },\n  {\n    text: 'Shapes',\n    collapsed: true,\n    items: [\n      { text: 'Box', link: '/guide/shapes/box' },\n      { text: 'CatmullRomCurve3', link: '/guide/shapes/catmullromcurve3' },\n      { text: 'Circle', link: '/guide/shapes/circle' },\n      { text: 'Cone', link: '/guide/shapes/cone' },\n      { text: 'CubicBezierLine', link: '/guide/shapes/cubic-bezier-line' },\n      { text: 'Cylinder', link: '/guide/shapes/cylinder' },\n      { text: 'Dodecahedron', link: '/guide/shapes/dodecahedron' },\n      { text: 'Icosahedron', link: '/guide/shapes/icosahedron' },\n      { text: 'Line2', link: '/guide/shapes/line2' },\n      { text: 'Octahedron', link: '/guide/shapes/octahedron' },\n      { text: 'Plane', link: '/guide/shapes/plane' },\n      { text: 'QuadraticBezierLine', link: '/guide/shapes/quadratic-bezier-line' },\n      { text: 'Ring', link: '/guide/shapes/ring' },\n      { text: 'RoundedBox', link: '/guide/shapes/rounded-box' },\n      { text: 'ScreenQuad', link: '/guide/shapes/screen-quad' },\n      { text: 'Sphere', link: '/guide/shapes/sphere' },\n      { text: 'Superformula', link: '/guide/shapes/superformula' },\n      { text: 'Tetrahedron', link: '/guide/shapes/tetrahedron' },\n      { text: 'Torus', link: '/guide/shapes/torus' },\n      { text: 'TorusKnot', link: '/guide/shapes/torus-knot' },\n      { text: 'Tube', link: '/guide/shapes/tube' },\n    ],\n  },\n  {\n    text: 'Staging',\n    items: [\n      { text: 'Backdrop', link: '/guide/staging/backdrop' },\n      { text: 'Environment', link: '/guide/staging/environment' },\n      { text: 'useEnvironment', link: '/guide/staging/use-environment' },\n      { text: 'Sky', link: '/guide/staging/sky' },\n      { text: 'Stars', link: '/guide/staging/stars' },\n      { text: 'Smoke', link: '/guide/staging/smoke' },\n      { text: 'AccumulativeShadows', link: '/guide/staging/accumulative-shadows' },\n      { text: 'ContactShadows', link: '/guide/staging/contact-shadows' },\n      { text: 'Precipitation', link: '/guide/staging/precipitation' },\n      { text: 'Sparkles', link: '/guide/staging/sparkles' },\n      { text: 'Ocean', link: '/guide/staging/ocean' },\n      { text: 'Fit', link: '/guide/staging/fit' },\n      { text: 'Align', link: '/guide/staging/align' },\n      { text: 'SoftShadows', link: '/guide/staging/soft-shadows' },\n      { text: 'Grid', link: '/guide/staging/grid' },\n      { text: 'CircleShadow', link: '/guide/staging/circle-shadow' },\n      { text: 'Bounds', link: '/guide/staging/bounds' },\n      { text: 'RandomizedLights', link: '/guide/staging/randomized-lights' },\n      { text: 'Stage', link: '/guide/staging/stage' },\n    ],\n  },\n  {\n    text: 'Misc',\n    collapsed: true,\n    items: [\n      { text: 'Stats', link: '/guide/misc/stats' },\n      { text: 'Html', link: '/guide/misc/html-component' },\n      { text: 'StatsGl', link: '/guide/misc/stats-gl' },\n      { text: 'useGLTFExporter', link: '/guide/misc/use-gltf-exporter' },\n      { text: 'BakeShadows', link: '/guide/misc/bake-shadows' },\n      { text: 'useIntersect', link: '/guide/misc/use-intersect' },\n      { text: 'LOD', link: '/guide/misc/lod' },\n    ],\n  },\n] as { text: string, items: { text: string, link: string }[] }[]\n\nexport const icons = {\n  abstractions: '📦',\n  controls: '🕹️',\n  staging: '🎭',\n  loaders: '⏳',\n  materials: '👔',\n  directives: '📢',\n  shapes: '🔷',\n  misc: '🛠️',\n}\n"
  },
  {
    "path": "docs/component-list/index.md",
    "content": "# Components\n\n<CientosComponentListGridView />\n"
  },
  {
    "path": "docs/guide/abstractions/animated-sprite.md",
    "content": "# AnimatedSprite\n\n<DocsDemo>\n  <AnimatedSpriteDemo />\n</DocsDemo>\n\n`<AnimatedSprite />` displays 2D animations defined in a [texture atlas](https://en.wikipedia.org/wiki/Texture_atlas). A typical `<AnimatedSprite />` will use:\n\n* an image containing multiple sprites\n* a JSON atlas containing the individual sprite coordinates in the image\n\n## Usage\n\n<<< @/.vitepress/theme/components/AnimatedSpriteDemo.vue{3,12-20}\n\n::: warning Suspense\n`<AnimatedSprite />` loads resources asynchronously, so it must be wrapped in a `<Suspense />`.\n:::\n\n## Compiling an atlas\n\nIn typical usage, `<AnimatedSprite />` requires both the URL to a texture of compiled sprite images and a JSON atlas containing information about the sprites in the texture.\n\n* [example compiled texture](https://raw.githubusercontent.com/Tresjs/assets/main/textures/animated-sprite/cientosTexture.png)\n* [example JSON atlas](https://raw.githubusercontent.com/Tresjs/assets/main/textures/animated-sprite/cientosAtlas.json)\n\nCompiling source images into a texture atlas is usually handled by third-party software. You may find [TexturePacker](https://www.codeandweb.com/texturepacker) useful.\n\n## Without an atlas\n\nThere may be cases where you don't want to supply an atlas to the `atlas` prop. To do so:\n\n* Compile your source images into a single image texture.\n* Space each sprite into equally sized columns and rows in the compiled image texture.\n* Ensure no extra padding has been added to the compiled image texture.\n* Set the `atlas` prop to number of columns, number of rows as `[number, number]`.\n\n## Spritesheets in the wild\n\n::: warning\nIn the wild, spritesheets are often distributed without atlases and the images are often compiled by hand. It can be difficult or impossible to use these resources directly with `<AnimatedSprite />`. In many cases, it's advisable to recompile the spritesheet.\n:::\n\n### How to recompile an existing spritesheet image\n\n* Cut individual sprites from the spritesheet and paste them into separate layers in an image editing application, e.g., GIMP.\n* Align the layers for animation. Toggling layer visibility on/off will show you how the animation will display, frame to frame.\n* Export layers as individual images.\n* Name the individual images according to the following pattern: <br>`[animation name][frame number].[extension]` <br>E.g., walk000.png, walk001.png, idle000.png, idle001.png\n* Compile individual images into an image texture and atlas using a texture packing application, like TexturePacker.\n\n## Props\n\n<table>\n<thead>\n<tr><th>Name</th><th>Description</th><th>Default</th></tr>\n</thead>\n<tbody>\n<tr><td>image</td><td><code>string</code> –\n  URL of the image texture or an image dataURL. This prop is not reactive.\n</td><td></td></tr>\n<tr><td>atlas</td><td><code>string | Atlasish</code> –\n  <ul>\n   <li>If <code>string</code>, the URL of the JSON atlas.</li>\n   <li>If <code>number</code>, the number of columns in the texture.</li>\n   <li>If <code>[number, number]</code>, the number of columns/rows in the texture.</li>\n   <li>If <code>AtlasData</code>, the atlas as a JS object.</li>\n  </ul>\n  <p>This prop is not reactive.</p>\n</td><td></td></tr>\n<tr><td>definitions</td><td><code>Record&lt;string, string&gt;</code> – Specify playback frame order and repeated frames (delays). <code>definitions</code> is a record where keys are atlas animation names and values are strings containing an animation definition.<br />\n  <p>A \"animation definition\" comma-separated string of frame numbers with optional parentheses-surrounded durations.</p>\n   <p>Here is how various definition strings convert to arrays of frames for playback:</p>\n  <ul>\n  <li>\"0,2,1\" - [0,2,1], i.e., play frame 0, 2, then 1.</li>\n  <li>\"2(10)\" - [2,2,2,2,2,2,2,2,2,2], i.e., play from 2 10 times.</li>\n  <li>\"1-4\" - [1,2,3,4]</li>\n  <li>\"10-5(2)\" - [10,10,9,9,8,8,7,7,6,6,5,5]</li>\n  <li>\"1-4(3),10(2)\" - [1,1,1,2,2,2,3,3,3,4,4,4,10,10]</li>\n  </ul>\n</td><td></td></tr>\n<tr><td>fps</td><td><code>number</code> – Desired frames per second of the animation.</td><td><code>30</code></td></tr>\n<tr><td>loop</td><td><code>boolean</code> – Whether or not the animation should loop.</td><td><code>true</code></td></tr>\n<tr><td>animation</td><td><code>string | [number, number] | number</code> – If <code>string</code>, name of the animation to play. If <code>[number, number]</code>, start and end frames of the animation. If <code>number</code>, frame number to display.</td><td><code>0</code></td></tr>\n<tr><td>paused</td><td><code>boolean</code> – Whether the animation is paused.</td><td><code>false</code></td></tr>\n<tr><td>reversed</td><td><code>boolean</code> – Whether to play the animation in reverse.</td><td><code>false</code></td></tr>\n<tr><td>flipX</td><td><code>boolean</code> – Whether the sprite should be flipped, left to right.</td><td><code>false</code></td></tr>\n<tr><td>resetOnEnd</td><td><code>boolean</code> – For a non-looping animation, when the animation ends, whether to display the zeroth frame.</td><td><code>false</code></td></tr>\n<tr><td>asSprite</td><td><code>boolean</code> – Whether to display the object as a THREE.Sprite. <a href=\"https://threejs.org/docs/?q=sprite#api/en/objects/Sprite\">See THREE.Sprite</a></td><td><code>true</code></td></tr>\n<tr><td>center</td><td><code>TresVector2</code> – Anchor point of the object. A value of [0.5, 0.5] corresponds to the center. [0, 0] is left, bottom.</td><td><code>[0.5, 0.5]</code></td></tr>\n<tr><td>alphaTest</td><td><code>number</code> – Alpha test value for the material. <a href=\"https://threejs.org/docs/#api/en/materials/Material.alphaTest\">See THREE.Material.alphaTest</a></td><td><code>0.0</code></td></tr>\n<tr><td>depthTest</td><td><code>boolean</code> – Depth test value for the material. <a href=\"https://threejs.org/docs/#api/en/materials/Material.depthTest\">See THREE.Material.depthTest</a></td><td><code>true</code></td></tr>\n<tr><td>depthWrite</td><td><code>boolean</code> – Depth write value for the material. <a href=\"https://threejs.org/docs/#api/en/materials/Material.depthWrite\">See THREE.Material.depthWrite</a></td><td><code>true</code></td></tr>\n</tbody>\n</table>\n\n## Events\n\n| Event | Description | Argument |\n| - | - | - |\n| `frame` | Emitted when the displayed animation frame changes – at most once per tick, frames may be dropped | `string` – Name of the newly displayed frame |\n| `end` | Emitted when the animation ends – `props.loop` must be set to `false` | `string` – Name of the ending frame |\n| `loop` | Emitted when the animation loops – `props.loop` must be set to `true` | `string` – Name of the frame at the end of the loop |\n\n## `animation`\n\nThe `:animation` prop holds either the name of the currently playing animation or a range of frames to play, or a frame number to display.\n\n### Using named animations as `animation`\n\nWhen individual files are converted to a spritesheet/atlas, typically the original images' filenames will be included in the atlas.\n\n`<AnimatedSprite />` uses those filenames to automatically group images into animations.\n\nUse either of the following naming conventions for your source images ...\n\n* `[animation name][frame number].[file_extension]`\n* `[animation name]_[frame number].[file_extension]`\n\n... then `<AnimatedSprite />` will automatically make all `[animation name]` available for playback. Just pass `[animation name]` to the component's `:animation` prop.\n\n#### Example\n\nFor our Cientos heart cartoon character animation, here's how the filenames map to animation names.\n\n| Filenames | Animation name |\n| - | - |\n| cientosIdle0000.png, cientosIdle0001.png, ... | cientosIdle |\n| cientosIdleToWalkTransition0000.png | cientosIdleToWalkTransition |\n| cientosWalk0000.png, cientosWalk0001.png, ... | cientosWalk |\n\nTry it out by clicking a few times on the character below:\n\n<DocsDemo>\n  <AnimatedSpriteNamedAnimationDemo />\n</DocsDemo>\n\n<<< @/.vitepress/theme/components/AnimatedSpriteNamedAnimationDemo.vue\n\n## `definitions`\n\nYou can supply an object to the `:definitions` prop. Any [named animation](#animation) can be a key. The value is a string that specifies frame order and delays.\n\n### Demo\n\nIn this demo, the 'idle' animation is comprised of six different images. By default, those images will play sequentially when the `:animation` prop is `'idle'`.\n\nBut below, we've added a `:definitions` prop with this value for the `idle` key:\n\n```\n'0-5, 0(10), 1-2, 3(20), 4-5, 0-5(3)'\n```\n\nSo, instead of playing images 0-5 sequentially, this animation will play instead:\n\n* `0-5` – Play all six images (`0-5`) of the animation normally.\n* `0(10), 1-2, 3(20), 4-5` – Play all six images again with a delay of ten frames at the bottom of the bounce (`0(10)`) and a delay of twenty frames at the top of the bounce (`3(20)`).\n* `0-5(3)` – Finally, play all six images of the animation with a delay of three frames each.\n\n<DocsDemo>\n  <AnimatedSpriteDefinitionsDemo />\n</DocsDemo>\n\n<<< @/.vitepress/theme/components/AnimatedSpriteDefinitionsDemo.vue{17-19}\n\n## `center`\n\nIn addition to being the sprite's anchor point, the `:center` prop also controls how differently sized source images will \"grow\" and \"shrink\". Namely, they \"grow out from\" and \"shrink towards\" the center.\n\nBelow is a simple animation containing differently sized source images. The anchor is visible at world position `0, 0, 0`.\n\n<DocsDemo>\n  <AnimatedSpriteCenterDemo />\n</DocsDemo>\n"
  },
  {
    "path": "docs/guide/abstractions/billboard.md",
    "content": "# Billboard\n\n<DocsDemo>\n  <BillboardDemo />\n</DocsDemo>\n\nAdds a `THREE.Group` that faces the camera.\n\n## Usage\n\n<<< @/.vitepress/theme/components/BillboardDemo.vue\n\n## Props\n\n| Prop             | Description                                          | Default       |\n| :--------------- | :--------------------------------------------------- | ------------- |\n| `autoUpdate`     | Whether the `<Billboard />` should face the camera automatically on every frame.       | `true`  |\n| `lockX`          | Whether to lock the x-axis.                          | `false` |\n| `lockY`          | Whether to lock the y-axis.                          | `false` |\n| `lockZ`          | Whether to lock the z-axis.                          | `false` |\n"
  },
  {
    "path": "docs/guide/abstractions/cube-camera.md",
    "content": "# CubeCamera\n\n<DocsDemo>\n  <CubeCameraDemo />\n</DocsDemo>\n\n`<CubeCamera />` creates a `THREE.CubeCamera` and uses it to render an environment map of your scene. The environment map is then applied to component's children.\n\n`<CubeCamera />` makes its children invisible while rendering to the internal buffer so that they are not included in the reflection.\n\n## Usage\n\n<<< @/.vitepress/theme/components/CubeCameraDemo.vue\n\n## Props\n\n| Prop             | Description                                          | Default       |\n| :--------------- | :--------------------------------------------------- | ------------- |\n| `frames`         | Number of frames to render. Set to `1` for a static scene. `Infinity` to update continuously.  | `Infinity`    |\n| `resolution`     | Resolution of the FBO                                | `255`         |\n| `near`           | Camera near                                          | `0.1`         |\n| `far`            | Camera far                                           | `1000`        |\n| `envMap`         | Custom environment map that is temporarily set as the scene's background | |\n| `fog`            | Custom fog that is temporarily set as the scene's fog | |\n"
  },
  {
    "path": "docs/guide/abstractions/edges.md",
    "content": "# Edges\n\n<DocsDemo>\n  <EdgesDemo />\n</DocsDemo>\n\nThe `cientos` package provides an abstraction of [EdgesGeometry](https://threejs.org/docs/#api/en/geometries/EdgesGeometry) from Three.js, `<Edges>` is specifically designed for rendering visible edges of objects in a scene graph. This enhances the visual quality by highlighting contours and providing a stylized appearance which contributes to the artistic aspect of 3D visualizations.\n\n## Usage\n\n<<< @/.vitepress/theme/components/EdgesDemo.vue\n\nThe `<Edges>` component is easy to set up as it automatically derives geometry from its parent. You can simply wrap it around any [Object3D](https://threejs.org/docs/#api/en/core/Object3D), [Mesh](https://threejs.org/docs/#api/en/objects/Mesh), or [primitive](https://docs.tresjs.org/advanced/primitive.html) to automatically apply edge rendering. You can provide a custom material to `<Edges>`. When a custom material is used, the color prop has no effect. *(see code bellow)*\n\n```vue\n<script setup lang=\"ts\">\nimport { Box, Edges } from '@tresjs/cientos'\n</script>\n\n<template>\n  <Box>\n    <TresMeshNormalMaterial />\n\n    <!-- Usage with the default material (LineBasicMaterial) -->\n    <Edges color=\"#FF0000\" />\n    <!-- ———— -->\n\n    <!-- Usage with an custom material -->\n    <Edges>\n      <TresMeshBasicMaterial color=\"#00FF00\" />\n    </Edges>\n    <!-- ———— -->\n  </Box>\n</template>\n```\n\n## Props\n\n`<Edges>` is based on [LineSegments](https://threejs.org/docs/#api/en/objects/LineSegments) & [Line](https://threejs.org/docs/#api/en/objects/Line) and supports all of its props.\n\n| Prop              | Description                                          | Default                   |\n| :---------------- | :--------------------------------------------------- | ------------------------- |\n| **color**        | `THREE.Color` — Color of the edges. <br> More informations : [TresColor](https://docs.tresjs.org/api/instances-arguments-and-props.html#colors) — [THREE.Color](https://threejs.org/docs/#api/en/math/Color) | `#ff0000`                   |\n| **threshold**        | `number` — An edge is only rendered if the angle (in degrees) between the face normals of the adjoining faces exceeds this value  | `1`                   |\n\n## Exposed properties\n\n| Event       | Description                                                      |\n| :---------- | :--------------------------------------------------------------- |\n| `instance` | Instance reference — Inheritance of [LineSegments](https://threejs.org/docs/#api/en/objects/LineSegments).|\n\n```typescript{1}\nconst edgesRef = shallowRef(null)\n\nconsole.log(edgesRef.value.instance) // instance properties\n```\n\n```vue{2}\n<template>\n    <Edges ref=\"edgesRef\" />\n</template>\n```\n"
  },
  {
    "path": "docs/guide/abstractions/fbo.md",
    "content": "# Fbo <Badge type=\"warning\" text=\"^3.5.0\" />\n\nAn FBO (or Frame Buffer Object) is generally used to render to a texture. This is useful for post-processing effects like blurring, or for rendering to a texture that will be used as a texture in a later draw call.\n\nCientos provides an `<Fbo />` component make it easy to use FBOs in your application.\n\n<DocsDemo>\n  <FboDemo />\n</DocsDemo>\n\n## Usage\n\n<<< @/.vitepress/theme/components/FboDemo.vue{3,15,48-51,58}\n\n## Props\n\n| Prop           | Description                                                                                                                                                            | Default              |\n| :------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------- |\n| **`width`**    | `number` - The width of the FBO.                                                                                                                                       | Width of the canvas  |\n| **`height`**   | `number` - the height of the FBO                                                                                                                                       | Height of the canvas |\n| **`depth`**    | `boolean` - Whether or not the FBO should render the depth to a [`depthTexture`](https://threejs.org/docs/?q=webglre#api/en/renderers/WebGLRenderTarget.depthTexture). | `false`              |\n| **`settings`** | `WebGLRenderTargetOptions` - Every other configuration property for the [`WebGLRenderTarget` class](https://threejs.org/docs/#api/en/renderers/WebGLRenderTarget)      | `{}`                 |\n| **`autoRender`** | `boolean` - Whether to automatically render the FBO on the default scene. | `true`               |\n"
  },
  {
    "path": "docs/guide/abstractions/global-audio.md",
    "content": "# GlobalAudio\n\nThe `cientos` package provides a `<GlobalAudio />` component that serves to easily add a global sound to your scene.\n\nReference: [Audio](https://threejs.org/docs/index.html?q=audio#api/en/audio/Audio)\n\n## Usage\n\n```vue{3,9}\n<script setup>\nimport { TresCanvas } from '@tresjs/core'\nimport { GlobalAudio } from '@tresjs/cientos'\n</script>\n\n<template>\n  <TresCanvas>\n    <TresPerspectiveCamera :position=\"[0, 0, 7.5]\" />\n    <GlobalAudio :src=\"exampleAudio\" />\n  </TresCanvas>\n</template>\n```\n\n*The `src` prop is required\n\n## Props\n\n| Prop           | Description                                              | Default               |\n| :------------- | :------------------------------------------------------- | --------------------- |\n| `src`          | Path to your audio file                                  |                       |\n| `playTrigger`  | Id of the DOM element that triggers the play/pause state | `renderer.domElement` |\n| `stopTrigger`  | Id of the DOM element that triggers the stop state       |                       |\n| `loop`         | If the audio must be replayed when ends                  | `false`               |\n| `volume`       | Volume of the audio                                      | `0.5`                 |\n| `playbackRate` | PlaybackRate of the audio                                | `1`                   |\n\n## Events\n\n| Event       | Description                                                      |\n| :---------- | :--------------------------------------------------------------- |\n| `isPlaying` | Dispatched when the Audio change its state (play, pause or stop) |\n"
  },
  {
    "path": "docs/guide/abstractions/gradient-texture.md",
    "content": "# GradientTexture\n\n<DocsDemo>\n  <GradientTextureDemo />\n</DocsDemo>\n\n`<GradientTexture />` creates a gradient in a THREE.Texture and attaches it to its parent THREE.Material's `map` by default.\n\n## Usage\n\n<<< @/.vitepress/theme/components/GradientTextureDemo.vue\n\n## Props\n\n| Prop             | Description                                          | Default       |\n| :--------------- | :--------------------------------------------------- | ------------- |\n| `stops`          | A `number[]` of values between `0` and `1` representing the color positions in the gradient. `stops.length` should match `color.length`.              |            |\n| `colors` | A `THREE.ColorRepresentation[]` representing the colors in the gradient.                          |            |\n| `attach`    | Where the component should be attached within its parent. | `'map'`           |\n| `height`    | Height of the canvas used to draw the gradient. | `1024` |\n| `width`     | Width of the canvas used to draw the gradient.  | `16`   |\n| `type`      | `'linear' \\| 'radial'` Type of gradient to draw. | `'linear'` |\n| `innerCircleRadius`     | Radius of the inner circle of a radial gradient.  | `0`   |\n| `outerCircleRadius`     | Radius of the outer circle of a radial gradient.  | `'auto'`   |\n\n<style scoped>\nimg {\n  width: 100%;\n}\n</style>\n"
  },
  {
    "path": "docs/guide/abstractions/image.md",
    "content": "# Image\n\n<DocsDemo>\n  <ImageDemo />\n</DocsDemo>\n\n`<Image />` is a shader-based component that optionally loads then displays an image texture on a default plane or on your custom geometry.\n\n## Usage\n\n<<< @/.vitepress/theme/components/ImageDemo.vue\n\n## Props\n\n::: info\n`<Image />` is a THREE.Mesh and most Mesh attributes can be used as props on the component.\n:::\n\n| Prop             | Description                                          | Default       |\n| :--------------- | :--------------------------------------------------- | ------------- |\n| `segments`          | Number of divisions in the default geometry.              | `1`           |\n| `scale` | Scale of the geometry. `number \\| [number, number]`                         | `1`           |\n| `color`    | Color multiplied into the image texture.                         | `'white'`           |\n| `zoom`          | Shrinks or enlarges the image texture. | `1` |\n| `radius`        | Border radius applied to the image texture. (Intended for rectangular geometries. Use with `transparent`.) | `0` |\n| `grayscale`        | Power of grayscale effect. 0 is off. 1 is full grayscale. | `0` |\n| `toneMapped`        | Whether this material is tone mapped according to the renderers toneMapping settings. [See THREE.material.tonemapped](https://threejs.org/docs/?q=material#api/en/materials/Material.toneMapped) | `0` |\n| `transparent` |  Whether the image material should be transparent. [See THREE.material.transparent](https://threejs.org/docs/?q=material#api/en/materials/Material.transparent) | `false` |\n| `transparent` |  Whether the image material should be transparent. [See THREE.material.transparent](https://threejs.org/docs/?q=material#api/en/materials/Material.transparent) | `false` |\n| `opacity` | Opacity of the image material. [See THREE.material.transparent](https://threejs.org/docs/?q=material#api/en/materials/Material.transparent) | `1` |\n| `side` | THREE.Side of the image material. [See THREE.material.side](https://threejs.org/docs/?q=material#api/en/materials/Material.side) | `FrontSide` |\n| `texture` | Image texture to display on the geometry. |  |\n| `url` | Image URL to load and display on the geometry. |  |\n"
  },
  {
    "path": "docs/guide/abstractions/lensflare.md",
    "content": "# Lensflare\n\n<DocsDemo>\n  <LensflareDemo />\n</DocsDemo>\n\n`<Lensflare />` wraps the [three.js Lensflare](https://threejs.org/docs/#examples/en/objects/Lensflare).\n\n## Usage\n\n```vue{3,9}\n<script setup lang=\"ts\">\nimport { TresCanvas } from '@tresjs/core'\nimport { Lensflare } from '@tresjs/cientos'\n</script>\n\n<template>\n  <TresCanvas>\n    <TresPointLight>\n      <Lensflare />\n    </TresPointLight>\n  </TresCanvas>\n</template>\n```\n\n## Props\n\n| Name | Description | Default |\n| :--- | :---------- | :------ |\n| **scale** |  `number` – scale of the lensflare | `1.0` |\n| **elements** | `Partial&lt;LensflareElementProps&gt;[]` – array of lensflare element properties | `undefined` |\n| **seed** | `number` – random seed for generating random seeded elements | `undefined` |\n| **seedProps** | `SeedProps[]` – specifications for generating random seeded elements | `undefined` |\n| **color** | `TresColor` – default color of lensflare elements | `undefined` |\n| **distance** | `number` – default distance of lensflare elements from flare center | `undefined` |\n| **size** | `number` – default size of lensflare elements | `undefined` |\n| **texture** | `Texture string[]` – default texture of lensflare elements | `undefined` |\n\n## `elements`\n\nYou can specify individual lensflare element properties directly using the component's `elements` prop.\n\nThe `elements` prop expects an instance of `(Partial<LensflareElementProps>)[]`.\n\nEvery object in `elements` may have any (or none) of the following properties.\n\n| Name         | Description                                                                   |\n| :----------- | :---------------------------------------------------------------------------- |\n| **texture**  | `string \\| Texture` - an image URL or texture to use on the lensflare element |\n| **color**    | `TresColor` - color of the lensflare element                                  |\n| **distance** | `number` - distance of the lensflare element from the lensflare center        |\n| **size**     | `number` - size of the lensflare element                                      |\n\n## `seed`\n\nAdding a `seed` prop to a component enables seeded random element generation.\n\nThe `seed` prop is used as the \"seed\" in a [pseudorandom number generator (PRNG)](https://en.wikipedia.org/wiki/Pseudorandom_number_generator). The PRNG is in turn used to build lensflare elements, by selecting values from an array of `SeedProps`.\n\n::: info\nIf you set a `seed` but not `seedProps`, the component will fall back to the default, built-in `SeedProps[]`.\n:::\n\n### Example\n\n```vue\n<Lensflare :seed=\"seedRef\" />\n```\n\nBelow, the results of setting `seedRef.value` to `0`, `1`, `2`, `3`, `4`, respectively.\n\n![Lensflare seeds 0-4](/cientos/lensflare_seeds.png)\n\n## `seedProps`\n\nAdding a `seedProps` prop to the component enables seeded random element generation.\n\nThe `seedProps` prop expects an instance of `SeedProps[]`. It specifies rules and acceptable values for creating random lensflare elements.\n\nEvery element in `seedProps` has this shape.\n\n| Name         | Description                                                                                                                        | Required |\n| :----------- | :--------------------------------------------------------------------------------------------------------------------------------- | -------- |\n| **texture**  | `string[]` - array of 1 or more image URLs; a single texture will be selected per generated element                                | yes      |\n| **color**    | `TresColor[]` - array of 1 or more colors; a single color will be selected per generated element                                   | yes      |\n| **distance** | `[number, number]` - minimum and maximum allowable distance from the flare center                                                  | yes      |\n| **size**     | `[number, number]` - minimum and maximum allowable size                                                                            | yes      |\n| **length**   | `[number, number]` - minimum and maximum allowable number of elements to generate                                                  | yes      |\n| **seed**     | `number` - if set, when this entry is processed, the random number generator with a combination of the incoming seed and this seed | no       |\n\n::: info\nIf you set `seedProps` but not `seed`, the component will fall back to a default `seed` of `0`.\n:::\n\n## Random elements and non-random properties\n\n`<Lensflare />` was designed to make it easy to get a lensflare on screen. You can simply add the component with no props and the component will generate seeded random lensflare elements.\n\n```vue\n<Lensflare />\n```\n\n### Non-random properties\n\nYou can provide a list of lensflare element properties using the [`elements`](#elements) prop.\n\n```vue\n<Lensflare :elements=\"[{ color: 'red' }, { color: 'yellow' }]\" />\n```\n\nThis will produce a lensflare with 2 elements. The first element will be red. The second will be yellow. The unspecified properties – `distance`, `size`, `texture` – will be filled in by the built-in defaults in this case.\n\nYou can also provide default props which will overwrite random generated props.\n\n```vue\n<Lensflare color:\"red\" />\n```\n\nSince `elements` is not defined here, the component will generate random lensflare elements. The specified `color` prop – \"red\" – will overwrite the color property of the generated lensflare elements.\n\nSee [precedence](#precedence) for details about how properties are filled in.\n\n### Random elements\n\nYou can let the component generate random elements ...\n\n... by not adding an [`elements` prop](#elements)\n\n```vue\n<Lensflare />\n```\n\n... by adding a [`seed` prop](#seed)\n\n```vue\n<Lensflare :seed=\"7127\" />\n```\n\n... by adding a [`seedProps` prop](#seedprops)\n\n```vue\n<Lensflare :seedProps=\"[{...}, {...}]\" />\n```\n\n### Mixing random elements and non-random properties\n\nYou can mix your own properties and random elements.\n\n```vue\n<Lensflare :elements=\"[{...}, {...}]\" :seed=\"8193\" />\n```\n\nHere, both `elements` and `seed` are defined. The component will generate random elements and overwrite their properties with the contents of `elements`, according to the [order of precedence](#precedence).\n\n:::info\nWhen mixing random elements with `elements`, the final number of lensflare elements equals whichever is **larger**, the length of the array of generated random elements or the length of `elements`.\n:::\n\n### Precedence\n\nIf more than one source sets the same property on a given element, the following order of precendence is used. Higher in the list (lower number) equals higher precendence.\n\n1. `elements`\n2. `color`, `distance`, `size`, `texture` – default element properties\n3. `seed`, `seedProps` – generated random elements\n4. built-in default element properties\n\n::: info\nIf `elements`, `seed`, and `seedProps` are all undefined, a `seed` of `0` and built-in default `seedProps` will be used to generate the lensflare elements.\n:::\n\n:::details Precedence example\n\nHere's an example of precedence. Assume this is in our vue template.\n\n```vue\n<Lensflare\n  :elements=\"[\n    {size:512, texture='http://example.net/circle.png'},\n    {color:'yellow', distance:0.5}\n  ]\"\n  :texture=\"http://example.net/ring.png\"\n  color=\"red\"\n  :size=\"256\"\n  :seed=\"1\"\n/>\n```\n\n`seed` is defined, so the component will produce random elements.\n\nAssume the random element generator produces this, based on `seed`:\n\n```js\n[\n  {\n    color: 'white',\n    distance: 0,\n    size: 1024,\n    texture: 'http://example.net/rays.png',\n  },\n  {\n    color: 'white',\n    distance: 1,\n    size: 512,\n    texture: 'http://example.net/circle.png',\n  },\n  {\n    color: 'white',\n    distance: 2,\n    size: 512,\n    texture: 'http://example.net/circle.png',\n  },\n]\n```\n\nWhen random elements are mixed with `elements`, the final number of elements in the lensflare is determined by whichever is longer.\n\nHere, `elements` contains 2 entries. The random element generator produced 3. So the resulting lensflare will have 3 elements.\n\nTherefore, resulting lensflare will have 3 elements.\n\nThe resulting 3 lensflare elements will have the following properties, from the following sources:\n\n```js\n[\n  {\n    color: 'yellow', // from `elements`\n    distance: 0, // from random element generator\n    size: 512, // from `elements`\n    texture: 'http://example.net/circle.png', // from `elements`\n  },\n  {\n    color: 'red', // from component prop `color`\n    distance: 0.5, // from `elements`\n    size: 256, // from component prop `size`\n    texture: 'http://example.net/ring.png', // from component prop `texture`\n  },\n  {\n    color: 'red', // from component prop `color`\n    distance: 2, // from random element generator\n    size: 256, // from component prop `size`\n    texture: 'http://example.net/ring.png', // from component prop `texture`\n  },\n]\n```\n\n:::\n"
  },
  {
    "path": "docs/guide/abstractions/levioso.md",
    "content": "# Levioso (Float)\r\n\r\n<DocsDemo>\r\n  <LeviosoDemo />\r\n</DocsDemo>\r\n\r\n![Leviosa](https://media.giphy.com/media/HaCFT5ghY6L1m/giphy.gif)\r\n\r\nThe `cientos` package provides a `<Levioso />` wrapper that makes its content … float, just like Magic 🪄✨\r\n\r\n## Usage\r\n\r\n<<< @/.vitepress/theme/components/Feather.vue\r\n\r\n## Props\r\n\r\n| Prop             | Description                                          | Default       |\r\n| :--------------- | :--------------------------------------------------- | ------------- |\r\n| `speed`          | Floating speed, higher it rocks more 🤘.              | `1`           |\r\n| `rotationFactor` | Factor for Euler rotation.                           | `1`           |\r\n| `floatFactor`    | Factor for Up/down movement.                         | `1`           |\r\n| `range`          | Range of y-axis values the object will float within. | `[-0.1, 0.1]` |\r\n\r\n<style scoped>\r\nimg {\r\n  width: 100%;\r\n}\r\n</style>\r\n"
  },
  {
    "path": "docs/guide/abstractions/marching-cubes.md",
    "content": "# MarchingCubes\n\n<DocsDemo>\n  <MarchingCubesDemo />\n</DocsDemo>\n\n`<MarchingCubes />` is a wrapper around [THREE's Marching Cubes](https://threejs.org/examples/#webgl_marchingcubes).\n\nIt includes 3 components:\n\n* `<MarchingCubes />` – container element for `<MarchingCube />`s and `<MarchingPlane />`s\n* `<MarchingCube />` - an individual metaball\n* `<MarchingPlane />` – optional bounding plane that interacts with the metaballs\n\n## Usage\n\n<<< @/.vitepress/theme/components/MarchingCubesDemo.vue\n\n## Props\n\n| Prop | Description | Default |\n| :----| :---------- | ------- |\n| `resolution` | Resolution of the marching cube field. Higher resolution produces smoother meshes at the cost of performance and memory. | `28` |\n| `maxPolyCount` | Maximum number of polygons to generate.  | `10000` |\n| `enableUvs` | Whether UVs are enabled. | `false` |\n| `enableColors` | Whether vertex colors are enabled. | `false` |\n\n## `<MarchingCube />` Props\n\n| Prop | Description | Default |\n| :----| :---------- | ------- |\n| `strength` | How strongly this cube affects the marching cube field. | `0.5` |\n| `subtract` | How quickly strength moves to `0` over distance. | `12` |\n\n## `<MarchingPlane />` Props\n\n| Prop | Description | Default |\n| :----| :---------- | ------- |\n| `planeType` | Which axis the plane appears on. `'x' \\| 'y' \\| 'z'` | `'x'` |\n| `strength` | How strongly this plane affects the marching cube field. | `0.5` |\n| `subtract` | How quickly strength moves to `0` over distance. | `12` |\n"
  },
  {
    "path": "docs/guide/abstractions/mask.md",
    "content": "# Mask\n\n<DocsDemo>\n  <MaskDemo />\n</DocsDemo>\n\n`<Mask/>` uses the stencil buffer to cut out areas of the screen.\n\n::: warning\nTo use `<Mask />` you *must* add `:stencil=\"true\"` to your `<TresCanvas />`.\n\n`<Mask />` relies on the [stencil buffer](https://threejs.org/docs/#api/en/renderers/WebGLRenderer). In recent versions of THREE.js, by default, the stencil buffer is not created.\n:::\n\n## Usage\n\n<<< @/.vitepress/theme/components/MaskDemo.vue\n\n## Props\n\n| Prop           | Description                                                                                                                                                            | Default              |\n| :------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------- |\n| **`id`**    | Id of the stencil buffer to use. Each mask must have a `number` id. Multiple masks can refer to the same id. | |\n| **`colorWrite`** | Whether the colors of the mask's own material will leak through. | `false` |\n| **`depthWrite`** | Whether the depth of the mask's own material will leak through. | `false` |\n"
  },
  {
    "path": "docs/guide/abstractions/mouse-parallax.md",
    "content": "# MouseParallax\n\n<DocsDemo>\n  <MouseParallaxDemo />\n</DocsDemo>\n\n`<MouseParallax />` is a component that allows you to easily create a [parallax](https://en.wikipedia.org/wiki/Parallax) effect. The camera will update automatically according to the mouse position.\n\n## Usage\n\nYou only need to import it and add it to your template as `<MouseParallax />`. Additionally, you can pass the following props:\n\n`factor` is a number to increase the movement range of the camera. This could be an array of two values corresponding to the x and y values, in that order: `:factor=[x,y]`.\n\n`ease` is a number that smooths the movement. This could be an array of two values corresponding to the x and y values, in that order: `:ease=[x,y]`.\n\n`local` is a boolean that enables movement based on the position of the mouse on the canvas rather than the window.\n\n<<< @/.vitepress/theme/components/MouseParallaxDemo.vue{3,15-18}\n\n## Props\n\n| Prop         | Description                                                                 | Default |\n| :----------- | :-------------------------------------------------------------------------- | ------- |\n| **disabled** | Enable or disable the effect                                                | false   |\n| **factor**   | Increase the range of the parallax                                          | 2.5     |\n| **ease**     | Increase the camera movement speed                                          | 0.1     |\n| **local**    | Whether the mouse coordinates are calculated from the element or the window | false   |\n"
  },
  {
    "path": "docs/guide/abstractions/outline.md",
    "content": "# Outline\n\n`<Outline />` creates an inverted-hull outline using its parent's geometry. Supported parents are `<TresMesh>` and `<TresSkinnedMesh>`.\n\n<DocsDemo>\n  <OutlineDemo />\n</DocsDemo>\n\n## Usage\n\n<<< @/.vitepress/theme/components/OutlineDemo.vue\n\n## Props\n\n| Props        | Description                                                        | Default |\n|--------------|--------------------------------------------------------------------| ------- |\n| color        | Outline color                                                      | `'black'` |\n| screenspace  | Whether line thickness is independent of zoom                      | `false` |\n| opacity      | Outline opacity                                                    | `1` |\n| transparent  | Outline transparency                                               | `false` |\n| thickness    | Outline thickness                                                  | `0.05` |\n| angle        | Geometry crease angle (`0` is no crease).  See [BufferGeometryUtils.toCreasedNormals](https://threejs.org/docs/#examples/en/utils/BufferGeometryUtils.toCreasedNormals) | `Math.PI` |\n"
  },
  {
    "path": "docs/guide/abstractions/positional-audio.md",
    "content": "# PositionalAudio\n\n<DocsDemo>\n  <PositionalAudioDemo />\n</DocsDemo>\n\n---\n\nThe `cientos` package provides an abstraction of the [PositionalAudio](https://threejs.org/docs/index.html?q=posi#api/en/audio/PositionalAudio), `<PositionalAudio>` is an object specifically designed for controlling sounds in a scene graph space. This allows, for the simulation of various audio environments, creating a more immersive user experience.\n\n`<PositionalAudio>` includes a helper 🛠️ that allows you to view the directional cone of te audio. The helper is based on the [PositionalAudioHelper](https://threejs.org/docs/#examples/en/helpers/PositionalAudioHelper) class.\n\n## Usage\n\nThe `<PositionalAudio>` component is very simple to set up and use, allowing you to bring your 3D scenes to life.  All you need to do is call the `<PositionalAudio>` component and set the `url`. It must be wrapped around the `<Suspense>` component to enable it to load your audio asynchronously. 💥\n\n```vue\n<script setup lang=\"ts\">\nimport { Box, PositionalAudio } from '@tresjs/cientos'\nimport { onUnmounted, shallowRef } from 'vue'\n\nconst positionalAudioRef = shallowRef(null)\n\nonUnmounted(() => {\n  positionalAudioRef?.value?.dispose()\n})\n</script>\n\n<template>\n  <TresCanvas>\n    <Box :args=\"[1, 1, 1]\">\n      <TresMeshNormalMaterial />\n      <Suspense>\n        <PositionalAudio\n          ref=\"positionalAudioRef\"\n          url=\"your-sound.mp3\"\n        />\n      </Suspense>\n    </Box>\n  </TresCanvas>\n</template>\n```\n\n:::warning\nAudioContext is authorised when an user gesture has been made on the page. `:autoplay=\"true\"` cannot be activated if no user gesture has been made previously (https://goo.gl/7K7WLu).\nIf you are sure that there will be a user gesture before your `<PositionAudio>` component appears/is created, you can directly add `:ready=\"true\"` and `autoplay=\"true\"` for a direct launch.\n:::\n\n## How does it work?\n<img class=\"mx-auto\" src=\"/positional-audio/sketch.jpg\" />\n\n## Props\n\n| Prop              | Description                                          | Default                   |\n| :---------------- | :--------------------------------------------------- | ------------------------- |\n| **url**        | `string` - **required** — The path or URL to the file. |                    |\n| **helper**        | `boolean` — Selects whether helper mode is enabled. <br> *(Useful for visualising the angle of sound propagation)*  | `false`                   |\n| **distance**        | `number` — The distance at which the volume reduction starts taking effect. ***A non-negative number.***  | `1`                   |\n| **ready**        | `boolean` — Tells `<PositionalAudio>` that `AudioContext` is authorised because an user gesture has been made on the page. This is imperative, as `autoplay` cannot be activated if no user gesture has been made previously (https://goo.gl/7K7WLu). <br> | `false`                   |\n| **autoplay**        | `boolean` — Selects whether the audio is launched automatically. Please refer to the `ready` prop for a better understanding of how to use autoplay.  | `false`                   |\n| **loop**        | `boolean` — Specifies whether the audio should loop. |      `false`              |\n| **innerAngle**        | `number` —  A parameter for directional audio sources, this is an angle, inside of which there will be no volume reduction. |      `360`              |\n| **outerAngle**        | `number` —  A parameter for directional audio sources, this is an angle, outside of which the volume will be reduced to a constant value of `outerGain` prop. |      `0`              |\n| **outerGain**        | `number` —  A parameter for directional audio sources, this is the amount of volume reduction outside of the `outerAngle` prop. When the value is `0` no sound can be heard. |      `0`              |\n\n## Exposed properties\n\n| Event       | Description                                                      |\n| :---------- | :--------------------------------------------------------------- |\n| `instance` | Instance reference — Inheritance of [PositionalAudio](https://threejs.org/docs/index.html?q=posi#api/en/audio/PositionalAudio).|\n| `play()` | Play audio — *Cannot be fired if audio is already running.* |\n| `pause()` | Pause audio — *Cannot be fired if audio is already paused.* |\n| `stop()` | Stop audio — *Cannot be fired if audio is already stopped.* |\n| `dispose()` | Dispose component — Deletion of the AudioListener in the camera, disconnection of the audio source and deletion of the PositionalAudioHelper (if it exists). |\n\n```typescript{1,3,8}\nconst positionalAudioRef = shallowRef(null)\n\nconsole.log(positionalAudioRef.value.instance) // instance properties\n\nconst handlerAudio = (action: string) => {\n  if (!positionalAudioRef.value) return\n\n  const { play, pause, stop } = positionalAudioRef.value\n\n  if (action === 'play') play()\n  else if (action === 'pause') pause()\n  else if (action === 'stop') stop()\n}\n```\n\n```vue{2-4,9}\n<template>\n  <button @click=\"handlerAudio('play')\">play</button>\n  <button @click=\"handlerAudio('pause')\">pause</button>\n  <button @click=\"handlerAudio('stop')\">stop</button>\n\n <TresCanvas>\n   <Sphere>\n      <Suspense>\n        <PositionalAudio ref=\"positionalAudioRef\" />\n      </Suspense>\n    </Sphere>\n  </TresCanvas>\n</template>\n```\n\n## Events\n\n| Event       | Description                                                      |\n| :---------- | :--------------------------------------------------------------- |\n| `is-playing` | Triggered when the audio changes its state (play, pause, or stop) <br> `@is-playing=\"(e) => yourIsPlayingRef = e\"` |\n"
  },
  {
    "path": "docs/guide/abstractions/reflector.md",
    "content": "# Reflector\n\n<DocsDemo>\n  <ReflectorDemo />\n</DocsDemo>\n\nThe `cientos` package provides an abstraction of the [Reflector class](https://github.com/mrdoob/three.js/blob/dev/examples/jsm/objects/Reflector.js), which creates a Mesh showing a real-time reflection of your scene.  This Mesh extends from `Mesh` so all the default props can be passed as well:\n\n## Usage\n\n<<< @/.vitepress/theme/components/ReflectorDemo.vue{6,26-32}\n\n## Props\n\n| Prop              | Description                                          | Default                   |\n| :---------------- | :--------------------------------------------------- | ------------------------- |\n| **color**         | The base color that's combine with the mirror effect | '#333'                 |\n| **textureWidth**  | the width of the texture to render on the mirror     | 512                       |\n| **textureHeight** | the height of the texture to render on the mirror    | 512                       |\n| **clipBias**      | to use the clipBias property                         | 0                         |\n| **multisample**   | how many samplers will be render                     | 4                         |\n| **shader**        | The texture of the smoke.                            | Reflector.ReflectorShader |\n\n::: warning\nAll the props except the `color`, are not reactive\n:::\n\n## Custom mirror effect\n\nFor more complex effect you can provide your own shaders, you could do this creating an object and pass the uniforms, vertexShaders or fragmentShaders:\n\n```vue{2,4-6,15}\n<script setup lang=\"ts\" >\nimport vertexShader from \"MyCustomVertexShader.glsl\"\n\nconst customShader = {\n  vertexShader\n}\n<script>\n<template>\n  <TresCanvas shadows alpha>\n    <TresPerspectiveCamera :position=\"[0, 0, 3]\" />\n    ...\n    <Reflector :rotation=\"[-Math.PI * 0.5, 0, 0]\"\n    :position-y=\"-2\"\n    color=\"#fff\"\n    :shader=\"customShader\"\n    >\n      <TresCircleGeometry :args=\"[10, 10]\" />\n    </Reflector>\n...\n  </TresCanvas>\n</template>\n```\nThe Reflector shader use the following configuration by default:\n\nYou can extend, modify or just play with them\n\n### Default shader\n\n```js\nconst shader = {\n  name: 'ReflectorShader',\n  uniforms: {\n    color: {\n      value: null\n    },\n    tDiffuse: {\n      value: null\n    },\n    textureMatrix: {\n      value: null\n    }\n  },\n  vertexShader: /* glsl */`\n  uniform mat4 textureMatrix;\n  varying vec4 vUv;\n\n  #include <common>\n  #include <logdepthbuf_pars_vertex>\n\n  void main() {\n    vUv = textureMatrix * vec4( position, 1.0 );\n    gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n\n    #include <logdepthbuf_vertex>\n\n  }`,\n  fragmentShader: /* glsl */`\n  uniform vec3 color;\n  uniform sampler2D tDiffuse;\n  varying vec4 vUv;\n\n  #include <logdepthbuf_pars_fragment>\n\n  float blendOverlay( float base, float blend ) {\n    return( base < 0.5 ? ( 2.0 * base * blend ) : ( 1.0 - 2.0 * ( 1.0 - base ) * ( 1.0 - blend ) ) );\n  }\n\n  vec3 blendOverlay( vec3 base, vec3 blend ) {\n    return vec3( blendOverlay( base.r, blend.r ), blendOverlay( base.g, blend.g ), blendOverlay( base.b, blend.b ) );\n  }\n\n  void main() {\n    #include <logdepthbuf_fragment>\n\n    vec4 base = texture2DProj( tDiffuse, vUv );\n    gl_FragColor = vec4( blendOverlay( base.rgb, color ), 1.0 );\n\n    #include <tonemapping_fragment>\n    #include <colorspace_fragment>\n  }`\n\n}\n```\n"
  },
  {
    "path": "docs/guide/abstractions/sampler.md",
    "content": "# Sampler <Badge type=\"warning\" text=\"^3.7.0\" />\n\nDeclarative abstraction around MeshSurfaceSampler & InstancedMesh. It samples points from the passed mesh and transforms an InstancedMesh's matrix to distribute instances on the points.\n\n<DocsDemo>\n  <SamplerDemo />\n</DocsDemo>\n\n## Usage\n\n`Experience.vue`\n\n<<< @/.vitepress/theme/components/SamplerDemo.vue{4,12-21}\n\n## Props\n\n| Props        | Description                                                        |\n|--------------|--------------------------------------------------------------------|\n| mesh         | **Mesh** Surface mesh from which to sample                         |\n| count        | **Number** Number of samples                                       |\n| instanceMesh | **InstanceMesh** InstanceMesh to scatter                           |\n| weight       | **String** A vertex attribute to be used as a weight when sampling |\n| transform    | **Function** A function that can be used as a custom sampling      |\n"
  },
  {
    "path": "docs/guide/abstractions/screen-sizer.md",
    "content": "# ScreenSizer\n\n<DocsDemo>\n  <ScreenSizerDemo />\n</DocsDemo>\n\nAdds a `<TresObject3D />` wrapper that scales to \"screen space\". By default `1` THREE world unit will be translated to 1 screen pixel.\n\nE.g. a BoxGeometry with a height, width, and depth of 100 each, will be scaled to 100 screen pixels in each dimension.\n\n## Usage\n\n<<< @/.vitepress/theme/components/ScreenSizerDemo.vue\n\n## Props\n\nInherits all props from `THREE.Object3D`.\n"
  },
  {
    "path": "docs/guide/abstractions/screen-space.md",
    "content": "# ScreenSpace\n\n<DocsDemo>\n  <ScreenSpaceDemo />\n</DocsDemo>\n\n`<ScreenSpace />` wraps its children in a `<TresGroup />` and positions them in front of the active camera at `:depth`.\n\n## Usage\n\n<<< @/.vitepress/theme/components/ScreenSpaceDemo.vue\n\n## Props\n\n| Prop             | Description              | Default       |\n| :--------------- | :----------------------- | ------------- |\n| `depth`          | Distance from the camera | `1`           |\n"
  },
  {
    "path": "docs/guide/abstractions/text-3d.md",
    "content": "# Text3D\n\n`<Text3D />` is a component that renders text in 3D. It is a wrapper around the [TextGeometry](https://threejs.org/docs/#api/en/geometries/TextGeometry) class.\n\n<DocsDemo>\n  <Text3Demo />\n</DocsDemo>\n\n## Usage\n\nTo use the `<Text3D />` component you need to pass the `font` prop with the URL of the font JSON file you want to use. TextGeometry uses `typeface`.json generated fonts, you can generate yours [here](http://gero3.github.io/facetype.js/)\n\n```vue\n<template>\n  <TresCanvas>\n    <Suspense>\n      <Text3D\n        text=\"TresJS\"\n        font=\"/fonts/FiraCodeRegular.json\"\n      >\n        <TresMeshNormalMaterial />\n      </Text3D>\n    </Suspense>\n  </TresCanvas>\n</template>\n```\n\nNotice that you need to pass the `<TresMeshNormalMaterial />` component as a child of the `<Text3D />` component. This is because `<Text3D />` is a `Mesh` component, so it needs a material. The geometry is created automatically. Also you can pass the text as a slot or as a prop like this:\n\n```vue\n<template>\n  <TresCanvas>\n    <Suspense>\n      <Text3D font=\"/fonts/FiraCodeRegular.json\">\n        TresJS\n        <TresMeshNormalMaterial />\n      </Text3D>\n    </Suspense>\n  </TresCanvas>\n</template>\n```\n\nIn addition, you can use the power of Vue to add reactivity, but you need to apply the needUpdates prop, for example you can create a reactive value, apply a v-model and make the bound, the Text3D component will update\n\n```vue\n<template>\n  <input v-model=\"myReactiveText\" />\n  <TresCanvas>\n    <Suspense>\n      <Text3D\n        :text=\"myReactiveText\"\n        font=\"/fonts/FiraCodeRegular.json\"\n        center\n        need-updates\n      />\n    </Suspense>\n  </TresCanvas>\n</template>\n```\n\n## Props\n\n| Prop               | Description                                                            | Default |\n| :----------------- | :--------------------------------------------------------------------- | ------- |\n| **font**           | The font data or font name to use for the text.                        |         |\n| **text**           | The text to display.                                                   |         |\n| **size**           | The size of the text.                                                  | 0.5     |\n| **height**         | The height of the text.                                                | 0.2     |\n| **curveSegments**  | The number of curve segments to use when generating the text geometry. | 5       |\n| **bevelEnabled**   | A flag indicating whether beveling should be enabled for the text.     | true    |\n| **bevelThickness** | The thickness of the beveled edge on the text.                         | 0.05    |\n| **bevelSize**      | The size of the beveled edge on the text.                              | 0.02    |\n| **bevelOffset**    | The offset of the beveled edge on the text.                            | 0       |\n| **bevelSegments**  | The number of bevel segments to use when generating the text geometry. | 4       |\n| **center**         | To center the text                                                     | false   |\n| **needUpdates**    | This props add reactivity                                              | false   |\n\n## References\n\n<a id=\"1\">[1]</a>\nThis table was generated by [ChatGPT](https://chat.openai.com/chat) based on the Vue component props.\n"
  },
  {
    "path": "docs/guide/abstractions/use-animations.md",
    "content": "# useAnimations\n\n`useAnimations` is a composable that returns a `shallowReactive` with all the models actions based on the animations provided. It is a wrapper around the [AnimationMixer](https://threejs.org/docs/#api/en/animation/AnimationMixer) class.\n\n<StackBlitzEmbed projectId=\"tresjs-use-animations\" />\n\n## Usage\n\n### Basic Usage (Automatic Updates)\n\nBy default, `useAnimations` automatically updates the animation mixer on each frame using the `useLoop` composable:\n\n```ts\nimport { useAnimations, useGLTF } from '@tresjs/cientos'\n\nconst { state } = useGLTF('/models/ugly-naked-bunny.gltf')\n\nconst animations = computed(() => state.value?.animations || [])\nconst model = computed(() => state?.value?.scene)\nconst { actions } = useAnimations(animations, model)\n\nconst currentAction = ref()\n\nwatch(actions, (newActions) => {\n  currentAction.value = newActions.Greeting\n  currentAction.value.play()\n})\n```\n\n### Manual Updates\n\nFor more control over when the animation mixer updates, you can set `manualUpdate: true` and handle the updates yourself:\n\n```ts\nimport { useAnimations, useGLTF } from '@tresjs/cientos'\nimport { useLoop } from '@tresjs/core'\n\nconst { state } = useGLTF('/models/ugly-naked-bunny.gltf')\n\nconst animations = computed(() => state.value?.animations || [])\nconst model = computed(() => state?.value?.scene)\nconst { actions, mixer } = useAnimations(animations, model, {\n  manualUpdate: true,\n})\n\n// Handle updates manually\nconst { onBeforeRender } = useLoop()\nonBeforeRender(({ delta }) => {\n  mixer.value.update(delta)\n})\n\nconst currentAction = ref()\n\nwatch(actions, (newActions) => {\n  currentAction.value = newActions.Greeting\n  currentAction.value.play()\n})\n```\n\n## Options\n\n- `manualUpdate` (optional): When set to `true`, disables automatic animation mixer updates. You'll need to call `mixer.value.update(delta)` manually. Default is `false`.\n"
  },
  {
    "path": "docs/guide/abstractions/use-fbo.md",
    "content": "# useFBO <Badge type=\"warning\" text=\"^3.5.0\" />\n\nAn FBO (or Frame Buffer Object) is generally used to render to a texture. This is useful for post-processing effects like blurring, or for rendering to a texture that will be used as a texture in a later draw call.\n\nCientos provides a `useFBO` composable to make it easy to use FBOs in your application.\n\n::: warning\nThe `useFBO` composable must be used inside of a child component since it needs the context of TresCanvas.\n:::\n\n<DocsDemo>\n  <UseFBODemo />\n</DocsDemo>\n\n## Usage\n\n`FboCube.vue`\n\n<<< @/.vitepress/theme/components/FboCube.vue{2,4-11,20}\n\n`Experience.vue`\n\n<<< @/.vitepress/theme/components/UseFBODemo.vue{40}\n\n## Props\n\n| Prop           | Description                                                                                                                                                            | Default              |\n| :------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------- |\n| **`width`**    | `number` - The width of the FBO.                                                                                                                                       | Width of the canvas  |\n| **`height`**   | `number` - the height of the FBO                                                                                                                                       | Height of the canvas |\n| **`depth`**    | `boolean` - Whether or not the FBO should render the depth to a [`depthTexture`](https://threejs.org/docs/?q=webglre#api/en/renderers/WebGLRenderTarget.depthTexture). | `false`              |\n| **`settings`** | `WebGLRenderTargetOptions` - Every other configuration property for the [`WebGLRenderTarget` class](https://threejs.org/docs/#api/en/renderers/WebGLRenderTarget)      | `{}`                 |\n"
  },
  {
    "path": "docs/guide/abstractions/use-surface-sampler.md",
    "content": "# useSurfaceSampler <Badge type=\"warning\" text=\"^3.7.0\" />\n\nA hook to obtain the result of the <Sampler /> as a buffer. Useful for driving anything other than InstancedMesh via the Sampler.\n\n<DocsDemo>\n  <UseSurfaceSamplerDemo />\n</DocsDemo>\n\n## Usage\n\n<<< @/.vitepress/theme/components/UseSurfaceSamplerDemo.vue{4,10,19-29}\n\n## Props\n\n| Props        | Description                                                        |\n|--------------|--------------------------------------------------------------------|\n| mesh         | **Mesh** Surface mesh from which to sample                         |\n| count        | **Number** Number of samples                                       |\n| instanceMesh | **InstanceMesh** InstanceMesh to scatter                           |\n| weight       | **String** A vertex attribute to be used as a weight when sampling |\n| transform    | **Function** A function that can be used as a custom sampling      |\n"
  },
  {
    "path": "docs/guide/controls/camera-controls.md",
    "content": "# CameraControls <Badge type=\"warning\" text=\"^3.2.0\" />\n\n<DocsDemo>\n  <CameraControlsDemo />\n</DocsDemo>\n\n[CameraControls](https://github.com/yomotsu/camera-controls) is a camera controller similar to [OrbitControls](https://cientos.tresjs.org/guide/controls/orbit-controls.html) yet supports smooth transitions and more features.\n\nHowever, it is thirty party library for ThreeJS. So to use it you would need to install and import using [npm](https://www.npmjs.com/package/camera-controls).\n\nHere is where the fancy part begins. ✨\nThe `cientos` package provides a component called `<CameraControls />` that is a wrapper of the `CameraControls` from the [`camera-controls`](https://github.com/yomotsu/camera-controls) module.\n\nThe nicest part? You don't need to extend the catalog or pass any arguments.\nIt just works. 💯\n\n## Usage\n\n<<< @/.vitepress/theme/components/CameraControlsDemo.vue{4,15-18}\n\n::: warning\nIs really important that the Perspective camera is set first in the canvas. Otherwise might break.\n:::\n\n## Props\n\nCertainly! Here's the properties of the object in raw markdown table format:\n\n| Prop                      | Description                                                                                                                                                                               | Default                                                   |\n| :------------------------ | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------- |\n| **makeDefault**           | Whether to make this the default controls.                                                                                                                                                | `false`                                                   |\n| **camera**                | The camera to control.                                                                                                                                                                    | `undefined`                                               |\n| **domElement**            | The DOM element to listen to.                                                                                                                                                             | `undefined`                                               |\n| **minPolarAngle**         | Minimum vertical angle in radians.                                                                                                                                                        | `0`                                                       |\n| **maxPolarAngle**         | Maximum vertical angle in radians.                                                                                                                                                        | `Math.PI`                                                 |\n| **minAzimuthAngle**       | Minimum horizontal angle in radians.                                                                                                                                                      | `-Infinity`                                               |\n| **maxAzimuthAngle**       | Maximum horizontal angle in radians.                                                                                                                                                      | `Infinity`                                                |\n| **distance**              | Current distance.                                                                                                                                                                         | `camera.position.z`                                       |\n| **minDistance**           | Minimum distance for dolly. PerspectiveCamera only.                                                                                                                                       | `Number.EPSILON`                                          |\n| **maxDistance**           | Maximum distance for dolly. PerspectiveCamera only.                                                                                                                                       | `Infinity`                                                |\n| **infinityDolly**         | `true` to enable Infinity Dolly for wheel and pinch.                                                                                                                                      | `false`                                                   |\n| **minZoom**               | Minimum camera zoom.                                                                                                                                                                      | `0.01`                                                    |\n| **maxZoom**               | Maximum camera zoom.                                                                                                                                                                      | `Infinity`                                                |\n| **smoothTime**            | Approximate time in seconds to reach the target. A smaller value will reach the target faster.                                                                                            | `0.25`                                                    |\n| **draggingSmoothTime**    | The smoothTime while dragging.                                                                                                                                                            | `0.125`                                                   |\n| **maxSpeed**              | Max transition speed in units per second.                                                                                                                                                 | `Infinity`                                                |\n| **azimuthRotateSpeed**    | Speed of azimuth (horizontal) rotation.                                                                                                                                                   | `1.0`                                                     |\n| **polarRotateSpeed**      | Speed of polar (vertical) rotation.                                                                                                                                                       | `1.0`                                                     |\n| **dollySpeed**            | Speed of mouse-wheel dollying.                                                                                                                                                            | `1.0`                                                     |\n| **dollyDragInverted**     | `true` to invert direction when dollying or zooming via drag.                                                                                                                             | `false`                                                   |\n| **truckSpeed**            | Speed of drag for truck and pedestal.                                                                                                                                                     | `2.0`                                                     |\n| **dollyToCursor**         | `true` to enable Dolly-in to the mouse cursor coords.                                                                                                                                     | `false`                                                   |\n| **dragToOffset**          | Whether to drag to offset.                                                                                                                                                                | `false`                                                   |\n| **verticalDragToForward** | The same as `.screenSpacePanning` in three.js's OrbitControls.                                                                                                                            | `false`                                                   |\n| **boundaryFriction**      | Friction ratio of the boundary.                                                                                                                                                           | `0.0`                                                     |\n| **restThreshold**         | Controls how soon the `rest` event fires as the camera slows.                                                                                                                             | `0.01`                                                    |\n| **colliderMeshes**        | An array of Meshes to collide with the camera. Be aware colliderMeshes may decrease performance. The collision test uses 4 raycasters from the camera since the near plane has 4 corners. | `[]`                                                      |\n| **mouseButtons**          | Configuration of actions on mouse input.                                                                                                                                                  | See [`User input config`](#user-input-config) for details |\n| **touches**               | Configuration of actions on touch.                                                                                                                                                        | See [`User input config`](#user-input-config) for details |\n\n## User input config\n\nYou can easily override the default user input config by defining `mouseButtons` and/or `touches` props that correspond to [`camera-controls` settings](https://github.com/yomotsu/camera-controls?#user-input-config). For ease of use, we're re-exporting the `CameraControls` class as `BaseCameraControls` which gives you access to the `ACTION` enum.\n\n```vue\n<script lang=\"ts\" setup>\nimport { BaseCameraControls, CameraControls } from '@tresjs/cientos'\n</script>\n\n<template>\n  ...\n  <CameraControls\n    :mouse-buttons=\"{ left: BaseCameraControls.ACTION.DOLLY }\"\n    :touches=\"{ one: BaseCameraControls.ACTION.TOUCH_TRUCK }\"\n  />\n  ...\n</template>\n```\n\n### Mouse buttons\n\n| Button to assign        | Options                                                        | Default                                                         |\n| ----------------------- | -------------------------------------------------------------- | --------------------------------------------------------------- |\n| `mouseButtons.left`     | `ROTATE` \\| `TRUCK` \\| `OFFSET` \\| `DOLLY` \\| `ZOOM` \\| `NONE` | `ROTATE`                                                        |\n| `mouseButtons.right`    | `ROTATE` \\| `TRUCK` \\| `OFFSET` \\| `DOLLY` \\| `ZOOM` \\| `NONE` | `TRUCK`                                                         |\n| `mouseButtons.wheel` ¹  | `ROTATE` \\| `TRUCK` \\| `OFFSET` \\| `DOLLY` \\| `ZOOM` \\| `NONE` | `DOLLY` for Perspective camera, `ZOOM` for Orthographic camera. |\n| `mouseButtons.middle` ² | `ROTATE` \\| `TRUCK` \\| `OFFSET` \\| `DOLLY` \\| `ZOOM` \\| `NONE` | `DOLLY`                                                         |\n\n1. Mouse wheel event for scroll \"up/down\", on mac \"up/down/left/right\".\n2. Mouse wheel \"button\" click event.\n\n### Touches\n\n| Fingers to assign | Options                                                                                                                                                                                                                                 | Default                                                                                |\n| ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |\n| `touches.one`     | `TOUCH_ROTATE` \\| `TOUCH_TRUCK` \\| `TOUCH_OFFSET` \\| `DOLLY` \\| `ZOOM` \\| `NONE`                                                                                                                                                        | `TOUCH_ROTATE`                                                                         |\n| `touches.two`     | `TOUCH_DOLLY_TRUCK` \\| `TOUCH_DOLLY_OFFSET` \\| `TOUCH_DOLLY_ROTATE` \\| `TOUCH_ZOOM_TRUCK` \\| `TOUCH_ZOOM_OFFSET` \\| `TOUCH_ZOOM_ROTATE` \\| `TOUCH_DOLLY` \\| `TOUCH_ZOOM` \\| `TOUCH_ROTATE` \\| `TOUCH_TRUCK` \\| `TOUCH_OFFSET` \\| `NONE` | `TOUCH_DOLLY_TRUCK` for Perspective camera, `TOUCH_ZOOM_TRUCK` for Othographic camera. |\n| `touches.three`   | `TOUCH_DOLLY_TRUCK` \\| `TOUCH_DOLLY_OFFSET` \\| `TOUCH_DOLLY_ROTATE` \\| `TOUCH_ZOOM_TRUCK` \\| `TOUCH_ZOOM_OFFSET` \\| `TOUCH_ZOOM_ROTATE` \\| `TOUCH_ROTATE` \\| `TOUCH_TRUCK` \\| `TOUCH_OFFSET` \\| `NONE`                                  | `TOUCH_TRUCK`                                                                          |\n\n## Events\n\n```vue\n<CameraControls @change=\"onChange\" @start=\"onStart\" @end=\"onEnd\" />\n```\n\n| Event      | Description                                   |\n| :--------- | :-------------------------------------------- |\n| **start**  | Dispatched when the control starts to change. |\n| **change** | Dispatched when the control changes.          |\n| **end**    | Dispatched when the control ends to change.   |\n"
  },
  {
    "path": "docs/guide/controls/helper.md",
    "content": "# Helper\n\n`<Helper />` handles instantiation, updates, and removal/disposal of THREE Helpers.\n\n<DocsDemo>\n  <HelperDemo />\n</DocsDemo>\n\n## Usage\n\n<<< @/.vitepress/theme/components/HelperDemo.vue\n\n## Props\n\n| Prop                | Description                                                                                   | Default     |\n| :------------------ | :-------------------------------------------------------------------------------------------- | ----------- |\n| **type**         | Helper constructor - required |       |\n| **args**         | Helper constructor args | `[]` |\n"
  },
  {
    "path": "docs/guide/controls/keyboard-controls.md",
    "content": "# KeyboardControls\n\n<DocsDemo>\n  <KeyboardControlsDemo />\n</DocsDemo>\n\n`<KeyboardControls />` is a simple keyboard controller for the camera. The camera's movements are bound to:\n\n* WASD on QWERTY keyboards or equivalent keys on non-QWERTY keyboards\n* Arrow keys\n\n::: info\n`<KeyboardControls />` uses `<PointerLockControls />` under the hood. You can use [`<PointerLockControls />` props and events](pointer-lock-controls#props).\n:::\n\n## Usage\n\n```vue{3,10}\n<script setup lang=\"ts\">\nimport { TresCanvas } from '@tresjs/core'\nimport { KeyboardControls, Box } from '@tresjs/cientos'\n</script>\n\n<template>\n  <TresCanvas>\n    <TresPerspectiveCamera />\n    <Box :position-y=\"0.5\" />\n    <KeyboardControls />\n    <TresGridHelper />\n  </TresCanvas>\n</template>\n```\n\n::: warning\nYou must add a `<TresPerspectiveCamera />` to your scene before adding `<KeyboardControls />`.\n:::\n\n## Props\n\n| Prop            | Description                          | Default |\n| :-------------- | :----------------------------------- | ------- |\n| **moveSpeed**   | Speed movement.                      | 0.2     |\n| **makeDefault** | If `true`, the controls will be set as the default controls for the scene.          | `true`     |\n| **camera**      | The camera to control.                                                              | `undefined` |\n| **domElement**  | The DOM element to listen to.                                                       | `undefined` |\n| **selector**    | Accept an id element as string. If set, the new element will be used as the trigger | `undefined` |\n\n## Events\n\n```vue\n<KeyboardControls @change=\"onChange\" @is-lock=\"(state) => isActive(state)\" />\n```\n\n| Event      | Description                                                      |\n| :--------- | :--------------------------------------------------------------- |\n| **isLock** | Return `true` if \"lock\", `false` if \"unlock\" events are triggered. |\n| **change** | Dispatched when the control changes.                             |\n"
  },
  {
    "path": "docs/guide/controls/map-controls.md",
    "content": "# MapControls\n\n<DocsDemo>\n  <MapControlsDemo />\n</DocsDemo>\n\n[MapControls](https://threejs.org/docs/index.html?q=controls#examples/en/controls/MapControls) similar to OrbitControls, this control is intended for transforming a camera over a map from bird's eye perspective, but uses a specific preset for mouse/touch interaction and disables screen space panning by default.\n\nHowever, as it is not part of the core of ThreeJS, to use it you would need to import it from the `three/examples/jsm/controls/MapControls` module.\n\nHere is where the fancy part begins. ✨\nThe `cientos` package provides a component called `<MapControls />`, which is a wrapper of the `MapControls` from the [`three-stdlib`](https://github.com/pmndrs/three-stdlib) module.\n\nThe nicest part? You don't need to extend the catalog or pass any arguments.\nIt just works. 💯\n\n## Usage\n\n<<< @/.vitepress/theme/components/MapControlsDemo.vue{3,9}\n\n::: warning\nIs really important that the Perspective camera is set first in the canvas. Otherwise might break.\n:::\n\n## Props\n\n| Prop              | Description                                                                                                      | Default     |\n| :---------------- | :--------------------------------------------------------------------------------------------------------------- | ----------- |\n| **makeDefault**   | If `true`, the controls will be set as the default controls for the scene.                                       | `false`     |\n| **camera**        | The camera to control.                                                                                           | `undefined` |\n| **domElement**    | The dom element to listen to.                                                                                    | `undefined` |\n"
  },
  {
    "path": "docs/guide/controls/orbit-controls.md",
    "content": "# OrbitControls\n\n<DocsDemo>\n  <OrbitControlsDemo />\n</DocsDemo>\n\n[OrbitControls](https://threejs.org/docs/index.html?q=orbit#examples/en/controls/OrbitControls) is a camera controller that allows you to orbit around a target. It's a great way to explore your scene.\n\nHowever, it is not part of the core of ThreeJS. So to use it you would need to import it from the `three/examples/jsm/controls/OrbitControls` module.\n\nHere is where the fancy part begins. ✨\nThe `cientos` package provides a component called `<OrbitControls />` that is a wrapper of the `OrbitControls` from the [`three-stdlib`](https://github.com/pmndrs/three-stdlib) module.\n\nThe nicest part? You don't need to extend the catalog or pass any arguments.\nIt just works. 💯\n\n## Usage\n\n<<< @/.vitepress/theme/components/OrbitControlsDemo.vue{3,9}\n\n::: warning\nIs really important that the Perspective camera is set first in the canvas. Otherwise might break.\n:::\n\n## Props\n\n| Prop                | Description                                                                                                                                                                      | Default                                                                          |\n| :------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- |\n| **makeDefault**     | If `true`, the controls will be set as the default controls for the scene.                                                                                                       | `false`                                                                          |\n| **camera**          | The camera to control.                                                                                                                                                           | `undefined`                                                                      |\n| **domElement**      | The dom element to listen to.                                                                                                                                                    | `undefined`                                                                      |\n| **target**          | The target to orbit around.                                                                                                                                                      | `undefined`                                                                      |\n| **enableDamping**   | If `true`, the controls will use damping (inertia), which can be used to give a sense of weight to the controls.                                                                 | `true`                                                                          |\n| **dampingFactor**   | The damping inertia used if `.enableDamping` is set to true.                                                                                                                     | `0.05`                                                                           |\n| **autoRotate**      | Set to true to automatically rotate around the target.                                                                                                                           | `false`                                                                          |\n| **autoRotateSpeed** | How fast to rotate around the target if `.autoRotate` is true.                                                                                                                   | `2`                                                                              |\n| **enablePan**       | Whether to enable panning.                                                                                                                                                       | `true`                                                                           |\n| **keyPanSpeed**     | How fast to pan the camera when the keyboard is used. Default is 7.0 pixels per keypress.                                                                                        | `7.0`                                                                            |\n| **keys**            | This object contains references to the keycodes for controlling camera panning. Default is the 4 arrow keys.                                                                     | `{ LEFT: 'ArrowLeft', UP: 'ArrowUp', RIGHT: 'ArrowRight', BOTTOM: 'ArrowDown' }` |\n| **maxAzimuthAngle** | How far you can orbit horizontally, upper limit. If set, the interval [ min, max ] must be a sub-interval of [ - 2 PI, 2 PI ], with ( max - min < 2 PI ). Default is Infinity.   | `Infinity`                                                                       |\n| **minAzimuthAngle** | How far you can orbit horizontally, lower limit. If set, the interval [ min, max ] must be a sub-interval of [ - 2 PI, 2 PI ], with ( max - min < 2 PI ). Default is - Infinity. | `-Infinity`                                                                      |\n| **maxPolarAngle**   | How far you can orbit vertically, upper limit. Range is 0 to Math.PI radians, and default is Math.PI.                                                                            | `Math.PI`                                                                        |\n| **minPolarAngle**   | How far you can orbit vertically, lower limit. Range is 0 to Math.PI radians, and default is 0.                                                                                  | `0`                                                                              |\n| **minDistance**     | The minimum distance of the camera to the target. Default is 0.                                                                                                                  | `0`                                                                              |\n| **maxDistance**     | The maximum distance of the camera to the target. Default is Infinity.                                                                                                           | `Infinity`                                                                       |\n| **minZoom**         | The minimum field of view angle, in radians. Default is 0.                                                                                                                       | `0`                                                                              |\n| **maxZoom**         | The maximum field of view angle, in radians. ( OrthographicCamera only ). Default is Infinity.                                                                                   | `Infinity`                                                                       |\n| **touches**         | This object contains references to the touch actions used by the controls.                                                                                                       | `{ ONE: TOUCH.ROTATE, TWO: TOUCH.DOLLY_PAN }`                                    |\n| **mouseButtons**    | This object contains references to the mouse actions used by the controls. LEFT: Rotate around the target, MIDDLE: Zoom the camera, RIGHT: Pan the camera.                       | `{ LEFT: MOUSE.ROTATE, MIDDLE: MOUSE.DOLLY, RIGHT: MOUSE.PAN }`                  |\n| -                   | -                                                                                                                                                                                |\n| **enableZoom**      | Whether to enable zooming.                                                                                                                                                       | `true`                                                                           |\n| **zoomSpeed**       | How fast to zoom in and out. Default is 1.                                                                                                                                       | `1`                                                                              |\n| **enableRotate**    | Whether to enable rotating.                                                                                                                                                      | `true`                                                                           |\n| **rotateSpeed**     | How fast to rotate around the target. Default is 1.                                                                                                                              | `1`                                                                              |\n\n## Events\n\n```vue\n<OrbitControls @change=\"onChange\" @start=\"onStart\" @end=\"onEnd\" />\n```\n\n| Event      | Description                                   |\n| :--------- | :-------------------------------------------- |\n| **start**  | Dispatched when the control starts to change. |\n| **change** | Dispatched when the control changes.          |\n| **end**    | Dispatched when the control ends to change.   |\n"
  },
  {
    "path": "docs/guide/controls/pointer-lock-controls.md",
    "content": "# PointerLockControls\n\n[PointerLockControls](https://threejs.org/docs/index.html?q=pointe#examples/en/controls/PointerLockControls) is a camera controller that allows you to capture the mouse movement and simulate a first person camera. It is a perfect choice for first person 3D games.\n\nHowever, as it is not part of the core of ThreeJS, to use it you would need to import it from the `three/examples/jsm/controls/PointerLockControls` module.\n\nHere is where the fancy part begins. ✨\nThe `cientos` package provides a component called `<PointerLockControls />`, which is a wrapper of the `PointerLockControls` from the [`three-stdlib`](https://github.com/pmndrs/three-stdlib) module.\n\nThe nicest part? You don't need to extend the catalog or pass any arguments.\nIt just works. 💯\n\n::: warning\nThis control uses the [Pointer Lock API](https://developer.mozilla.org/en-US/docs/Web/API/Pointer_Lock_API), the same rules are applied, for example, you need to interact with the browser to \"lock\" or start the event.\nIn addition, you need to wait 1 second between canceling and re-starting the event\n:::\n\n## Usage\n\n```vue{4}\n<template>\n  <TresCanvas shadows alpha>\n    <TresPerspectiveCamera :position=\"[0, 0, 3]\" />\n    <PointerLockControls />\n    <TresGridHelper :args=\"[10, 10]\" />\n\n  </TresCanvas>\n</template>\n```\n\nOr using your own HTML element to trigger the event\n\n```vue{3}\n<template>\n<button id=\"lock\">Lock</button>\n  <TresCanvas shadows alpha>\n    <TresPerspectiveCamera :position=\"[0, 0, 3]\" />\n    <PointerLockControls selector=\"lock\" />\n    <TresGridHelper :args=\"[10, 10]\" />\n\n  </TresCanvas>\n</template>\n```\n\n::: warning\nIs really important that the Perspective camera is set first in the canvas. Otherwise might break.\n:::\n\n## Props\n\n| Prop            | Description                                                                               | Default     |\n| :-------------- | :---------------------------------------------------------------------------------------- | ----------- |\n| **makeDefault** | If `true`, the controls will be set as the default controls for the scene.                | `false`     |\n| **camera**      | The camera to control.                                                                    | `undefined` |\n| **domElement**  | The dom element to listen to.                                                             | `undefined` |\n| **selector**    | Accept an id element as string, if it is set, the new element will be used as the trigger | `undefined` |\n\n## Events\n\n```vue\n<PointerLockControls @change=\"onChange\" @is-lock=\"(state) => isActive(state)\" />\n```\n\n| Event      | Description                                                      |\n| :--------- | :--------------------------------------------------------------- |\n| **isLock** | Return `true` if \"lock\", `false` if \"unlock\" events are trigger. |\n| **change** | Dispatched when the control changes.                             |\n"
  },
  {
    "path": "docs/guide/controls/scroll-controls.md",
    "content": "# ScrollControls\n\n<DocsDemo>\n  <ScrollControlsDemo />\n</DocsDemo>\n\n`ScrollControls` use scroll as a trigger for control the scene, you can use the HTML native scroll or use the one that it get creates for you.\n\nThe `cientos` package create this controls from scratch for you, and comes with really useful props to customize your experiences, try it out. ✨\n\n## Usage\n\nTo start using it, you just need to import it and play with it.\n\n<<< @/.vitepress/theme/components/ScrollControlsDemo.vue{3,14}\n\n::: warning\nIs really important that the Perspective camera is set first in the canvas. Otherwise might break.\n:::\n\nYou can use the `horizontal` prop, to makes the scroll horizontal way.\n\n<DocsDemo>\n  <ScrollControlsHorizontalDemo />\n</DocsDemo>\n\n<<< @/.vitepress/theme/components/ScrollControlsHorizontalDemo.vue{3,14}\n\nWith the `pages` prop you can control the length of the scroll, and with the `distance` you can control how much movement is apply to the objects ( you can for example use it with 0 value and use the progress element)\n\nIn addition a nice effect could be achieve by using the `smoothScroll` prop like so:\n<DocsDemo>\n  <ScrollControlsPagesDemo />\n</DocsDemo>\n\n<<< @/.vitepress/theme/components/ScrollControlsPagesDemo.vue{14-18}\n\nBy default `ScrollControls` creates a scroll around the canvas and takes the camera as a default for animate, also it comes with a reactive `progress` param that returns a normalized value from 0 (start point) to 1 (end point) you just need to attach it to a v-model.\n\n<DocsDemo>\n  <ScrollControlsProgressDemo />\n</DocsDemo>\n\n<<< @/.vitepress/theme/components/ScrollControlsProgressDemo.vue{7,27-30}\n\nIf you don't want to use the default camera movement you can set the distance to 0 a just rely on progress to animate (the progress is not affected by the `smoothScroll` )\n\n<DocsDemo>\n  <ScrollControlsProgressCameraDemo />\n</DocsDemo>\n\nBut it's not all, you can also pass the `htmlScroll` props this will deactivate the custom scroll and use the native html scroll.\n\n```vue{1}\n    <ScrollControls htmlScroll />\n```\n\n::: warning\n- If you set the `htmlScroll` you need to set your html to have content that create scroll. so the `pages` prop will not work\n- The `htmlScroll` will set the TresCanvas as a fixed background.\n:::\n\n### Slots\n\nThe elements that you pass as a slot will be affected by the scroll effect, and follow the camera.\n\n<DocsDemo>\n  <ScrollControlsSlotsDemo />\n</DocsDemo>\n\n<<< @/.vitepress/theme/components/ScrollControlsSlotsDemo.vue{31-43}\n\n## Props\n\n| Prop             | Description                                              | Default |\n| :--------------- | :------------------------------------------------------- | ------- |\n| **pages**        | The length of the scroll (not available with htmlScroll) | `4`     |\n| **distance**     | The distance to move the objects                         | `4`     |\n| **smoothScroll** | The smooth factor of the scrolling.                      | `0.1`   |\n| **horizontal**   | Whether the scroll is horizontal or vertical.            | `false` |\n| **htmlScroll**   | Whether to use the native HTML scroll.                   | `false` |\n\n::: warning\nCurrently the props are not reactive for this control\n:::\n"
  },
  {
    "path": "docs/guide/controls/transform-controls.md",
    "content": "# Transform Controls\n\nThe [Transform Controls](https://threejs.org/docs/#examples/en/controls/TransformControls) are a set of three gizmos that can be used to translate, rotate and scale objects in the scene. It adapts a similar interaction model of DCC tools like Blender\n\n<DocsDemo>\n  <TransformControlsDemo />\n</DocsDemo>\n\n## Usage\n\nTo use the Transform Controls, simply add the `TransformControls` component to your scene. You can pass the `templateRef`of the instance you want to control as a prop.\n\n```vue{2,6,8}\n<script setup>\nconst boxRef = shallowRef()\n</script>\n<template>\n  <TresCanvas>\n    <TresPerspectiveCamera :args=\"[45, 1, 0.1, 1000]\" />\n    <OrbitControls make-default />\n    <TransformControls :object=\"boxRef\" />\n    <TresMesh ref=\"boxRef\" :position=\"[0, 4, 0]\" cast-shadow>\n      <TresBoxGeometry :args=\"[1.5, 1.5, 1.5]\" />\n      <TresMeshToonMaterial color=\"#4F4F4F\" />\n    </TresMesh>\n  </TresCanvas>\n</template>\n```\n\n::: warning\nIf you are using other controls ([OrbitControls](/guide/controls/orbit-controls)) they will interfere with each other when dragging. To avoid this, you can set the `makeDefault` prop to `true` on the **OrbitControls**.\n:::\n\n## Modes\n\nThe Transform Controls can be used in three different modes:\n\n### Translate\n\n![Translate](/cientos/transform-controls-translate.png)\n\nThe default mode allows you to move the object around the scene.\n\n```vue\n<TransformControls mode=\"translate\" :object=\"sphereRef\" />\n```\n\n### Rotate\n\n![Rotate](/cientos/transform-controls-rotate.png)\n\nThe rotate mode allows you to rotate the object around the scene.\n\n```vue\n<TransformControls mode=\"rotate\" :object=\"boxRef\" />\n```\n\n### Scale\n\n![Scale](/cientos/transform-controls-scale.png)\n\nThe scale mode allows you to scale the object around the scene.\n\n```vue\n<TransformControls mode=\"scale\" :object=\"sphereRef\" />\n```\n\n## Props\n\n| Prop                | Description                                                                                   | Default     |\n| :------------------ | :-------------------------------------------------------------------------------------------- | ----------- |\n| **object**         | The instance [Object3D](https://threejs.org/docs/index.html#api/en/core/Object3D) to control. | `null`      |\n| **mode**            | The mode of the controls. Can be `translate`, `rotate` or `scale`.                            | `translate` |\n| **enabled**         | If `true`, the controls will be enabled.                                                      | `true`      |\n| **axis**            | The axis to use for the controls. Can be `X`, `Y`, `Z`, `XY`, `YZ`, `XZ`, `XYZ`.              | `XYZ`       |\n| **space**           | The space to use for the controls. Can be `local` or `world`.                                 | `local`     |\n| **size**            | The size of the controls.                                                                     | `1`         |\n| **translationSnap** | The distance to snap to when translating. (World units)                                       | `null`      |\n| **rotationSnap**    | The angle to snap to when rotating. (Radians)                                                 | `null`      |\n| **scaleSnap**       | The scale to snap to when scaling.                                                            | `null`      |\n| **showX**           | If `true`, the X-axis helper will be shown.                                                   | `true`      |\n| **showY**           | If `true`, the Y-axis helper will be shown.                                                   | `true`      |\n| **showZ**           | If `true`, the Z-axis helper will be shown.                                                   | `true`      |\n\n## Events\n\n| Event            | Description                                                    |\n| :--------------- | :------------------------------------------------------------- |\n| **dragging**     | Fired when the user starts or stops dragging the controls.     |\n| **change**       | Fired when the user changes the controls.                      |\n| **mouseDown**    | Fired when the user clicks on the controls.                    |\n| **mouseUp**      | Fired when the user releases the mouse button on the controls. |\n| **objectChange** | Fired when the user changes the object.                        |\n\n<style scoped>\nimg {\n    aspect-ratio: 16/9;\n    object-fit: cover;\n    object-position: top;\n    border-radius: 8px;\n}\n</style>\n"
  },
  {
    "path": "docs/guide/index.md",
    "content": "# Cientos\r\n\r\n![Cientos banner](/cientos-banner.png)\r\n\r\n> Cientos (Spanish word for \"hundreds\", pronounced `/θjentos/` ) is a collection of useful ready-to-go helpers and components that are not part of the [core](https://docs.tresjs.org/) package. The name uses the word in Spanish to multiply by 100, to refer to the potential reach of the package to hold amazing abstractions.\r\n\r\nThe `cientos` package uses [`three-stdlib`](https://github.com/pmndrs/three-stdlib) module under the hood instead of the `three/examples/jsm` module. This means that you don't need to extend the catalogue of components using the `extend` method, `cientos` does it for you.\r\n\r\nIt just works. 💯\r\n\r\n::: info\r\nThis package is not required to use the core library, but it improves DX, especially for complex scenes.\r\n:::\r\n\r\n## Installation\r\n\r\n::: code-group\r\n\r\n```bash [pnpm]\r\npnpm add @tresjs/cientos\r\n```\r\n\r\n```bash [npm]\r\nnpm install @tresjs/cientos\r\n\r\n```\r\n\r\n```bash [yarn]\r\nyarn add @tresjs/cientos\r\n```\r\n\r\n:::\r\n\r\n## Basic Usage\r\n\r\n```ts\r\nimport { OrbitControls } from '@tresjs/cientos'\r\n```\r\n\r\nNow you can use the `OrbitControls` component in your scene.\r\n\r\n```html\r\n<template>\r\n  <TresCanvas shadows alpha>\r\n    <TresPerspectiveCamera :args=\"[45, 1, 0.1, 1000]\" />\r\n    <OrbitControls />\r\n  </TresCanvas>\r\n</template>\r\r\n```\r\n\r\n::: warning\r\nNotice that you don't need to write the prefix `Tres` such as `<TresOrbitControl />` to use the component\r\n:::\r\n"
  },
  {
    "path": "docs/guide/loaders/fbx-model.md",
    "content": "# Using `FBXModel`\n\n<DocsDemo>\n  <FBXModelDemo />\n</DocsDemo>\n\nThe `FBXModel` component is a wrapper around [`useFBX`](./use-fbx.md) composable and accepts the same options as props.\n\n## Usage\n\n<<< @/.vitepress/theme/components/FBXModelDemo.vue{3,10-15}\n\n## Model reference\n\nYou can access the model reference by passing a `ref` to the `FBXModel` component and then using it to get the object.\n\n```vue\n<script setup lang=\"ts\">\nimport type { TresObject } from '@tresjs/core'\nimport { FBXModel, OrbitControls } from '@tresjs/cientos'\n\nconst modelRef = shallowRef<TresObject>()\n\nwatch(modelRef, (model) => {\n  // Do something with the model\n  model.position.set(0, 0, 0)\n})\n</script>\n\n<template>\n  <FBXModel\n    ref=\"modelRef\"\n    path=\"https://raw.githubusercontent.com/Tresjs/assets/main/models/fbx/low-poly-truck/Jeep_done.fbx\"\n  />\n</template>\n```\n\n## Props\n\n| Prop           | Description                                                | Default     |\n| :------------- | :--------------------------------------------------------- | ----------- |\n| `path`         | Path to the model file.                                    | `undefined` |\n| `castShadow`   | Apply `cast-shadow` to all meshes inside your model.      | `false`     |\n| `receiveShadow`| Apply `receive-shadow` to all meshes inside your model.   | `false`     |\n"
  },
  {
    "path": "docs/guide/loaders/gltf-model.md",
    "content": "# Using `GLTFModel`\n\n<DocsDemo>\n  <GLTFModelDemo />\n</DocsDemo>\n\nThe `GLTFModel` component is a wrapper around [`useGLTF`](./use-gltf.md) composable and accepts the same options as props.\n\n## Usage\n\n<<< @/.vitepress/theme/components/GLTFModelDemo.vue{3,10}\n\n## Model reference\n\nYou can access the model reference by passing a `ref` to the `model` prop and then using to get the object.\n\n```vue\n<script setup lang=\"ts\">\nimport type { TresObject } from 'tresjs'\nimport { GLTFModel, OrbitControls } from '@tresjs/cientos'\n\nconst modelRef = shallowRef<TresObject>()\n\nwatch(modelRef, (model) => {\n  // Do something with the model\n  model.position.set(0, 0, 0)\n})\n</script>\n\n<template>\n  <GLTFModel\n    ref=\"modelRef\"\n    path=\"https://raw.githubusercontent.com/Tresjs/assets/main/models/gltf/blender-cube.glb\"\n  />\n</template>\n```\n\n## Props\n\n| Prop          | Description                                                                                                           | Default     |\n| :------------ | :-------------------------------------------------------------------------------------------------------------------- | ----------- |\n| `path`        | Path to the model file.                                                                                               | `undefined` |\n| `draco`       | Enable [Draco compression](https://threejs.org/docs/index.html?q=drac#examples/en/loaders/DRACOLoader) for the model. | `false`     |\n| `decoderPath` | Path to a local Draco decoder.                                                                                        | `undefined` |\n| `castShadow`  | Apply `cast-shadow` to all meshes inside your model.                                                                  | `false`     |\n| `receiveShadow` | Apply `receive-shadow` to all meshes inside your model.                                                             | `false`     |\n"
  },
  {
    "path": "docs/guide/loaders/use-fbx.md",
    "content": "# useFBX\n\n<DocsDemo>\n  <UseFBXDemo />\n</DocsDemo>\n\nA composable that allows you to easily load FBX models into your **TresJS** scene.\n\n## Usage\n\n::: code-group\n```vue{2,6} [TheModel.vue]\n<script setup lang=\"ts\">\nimport { useFBX } from '@tresjs/cientos'\n\nconst path = 'https://raw.githubusercontent.com/'\n  + 'Tresjs/assets/main/models/fbx/low-poly-truck/Jeep_done.fbx'\nconst { state, nodes, materials } = useFBX(path)\n</script>\n\n<template>\n  <primitive v-if=\"state\" :object=\"state\" :scale=\"0.025\" />\n</template>\n```\n```vue [app.vue]\n<script setup lang=\"ts\">\nimport { OrbitControls } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport TheModel from './TheModel.vue'\n</script>\n\n<template>\n  <TresCanvas clear-color=\"#1F90FF\">\n    <TresPerspectiveCamera :position=\"[11, 11, 11]\" />\n    <OrbitControls />\n    <TheModel />\n    <TresDirectionalLight\n      :intensity=\"2\"\n      :position=\"[3, 3, 3]\"\n    />\n    <TresAmbientLight :intensity=\"1\" />\n  </TresCanvas>\n</template>\n```\n:::\n\n## Return Values\n\n| Name         | Type      | Description                                    |\n| :----------- | --------- | ---------------------------------------------- |\n| **state**    | `Group`   | The loaded FBX model state                     |\n| **nodes**    | `object`  | Computed object containing all nodes in the scene |\n| **materials**| `object`  | Computed object containing all materials in the scene |\n| **isLoading**| `boolean` | Whether the model is currently loading         |\n| **execute**  | `() => Promise<void>` | Function to reload the model |\n\n## Options\n\n| Name            | Type       | Description                                |\n| :-------------- | ---------- | ------------------------------------------ |\n| **traverse**    | `Function` | A traverse function applied to the scene upon loading the model. |\n\n## Accessing Nodes and Materials\n\nThe composable provides computed properties to easily access nodes and materials in your scene:\n\n```ts\nconst { nodes, materials } = useFBX('/model.fbx')\n\n// Access a specific node\nconst mesh = nodes.value.MeshName\n\n// Access a specific material\nconst material = materials.value.MaterialName\n```\n\nThis makes it easier to manipulate specific parts of your model or apply materials programmatically.\n"
  },
  {
    "path": "docs/guide/loaders/use-gltf.md",
    "content": "# useGLTF\n\n<DocsDemo>\n  <UseGLTFDemo />\n</DocsDemo>\n\nA composable that allows you to easily load glb/glTF models into your **TresJS** scene.\n\n## Usage\n\n::: code-group\n```vue{2,6} [TheModel.vue]\n<script setup lang=\"ts\">\nimport { useGLTF } from '@tresjs/cientos'\n\nconst path = './blender-cube.glb'\nconst { state, nodes, materials } = useGLTF(path, { draco: true })\n</script>\n\n<template>\n  <primitive v-if=\"state\" :object=\"state?.scene\" />\n</template>\n```\n```vue [app.vue]\n<script setup lang=\"ts\">\nimport { OrbitControls } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport TheModel from './TheModel.vue'\n</script>\n\n<template>\n  <TresCanvas clear-color=\"#F78B3D\">\n    <TresPerspectiveCamera :position=\"[3, 2, 5]\" />\n    <OrbitControls />\n    <TheModel />\n    <TresDirectionalLight\n      :intensity=\"2\"\n      :position=\"[3, 3, 3]\"\n    />\n    <TresAmbientLight :intensity=\"1\" />\n  </TresCanvas>\n</template>\n```\n\n:::\n\nAn advantage of using `useGLTF` is that you can pass a `draco` prop to enable [Draco compression](https://threejs.org/docs/index.html?q=drac#examples/en/loaders/DRACOLoader) for the model. This will reduce the size of the model and improve performance.\n\n```ts\nimport { useGLTF } from '@tresjs/cientos'\n\nconst { state, nodes, materials } = useGLTF('/models/AkuAku.gltf', { draco: true })\n```\n\n## Return Values\n\n| Name         | Type      | Description                                    |\n| :----------- | --------- | ---------------------------------------------- |\n| **state**    | `GLTF`    | The loaded GLTF model state                    |\n| **nodes**    | `object`  | Computed object containing all nodes in the scene |\n| **materials**| `object`  | Computed object containing all materials in the scene |\n| **isLoading**| `boolean` | Whether the model is currently loading         |\n| **progress** | `number`  | The progress of the model loading         |\n| **load**     | `() => Promise<void>` | Function to reload the model |\n\n## Options\n\n| Name            | Type       | Default     | Description                          |\n| :-------------- | ---------- | ----------- | ------------------------------------ |\n| **draco**       | `boolean`  | `false`     | Whether to enable Draco compression. |\n| **decoderPath** | `string`   | `'https://www.gstatic.com/draco/versioned/decoders/1.5.6/'` | Path to the Draco decoder.     |\n| **traverse**    | `Function` |             | A traverse function applied to the scene upon loading the model. |\n\n## Accessing Nodes and Materials\n\nThe composable provides computed properties to easily access nodes and materials in your scene:\n\n```ts\nconst { nodes, materials } = useGLTF('/model.glb')\n\n// Access a specific node\nconst mesh = nodes.value.MeshName\n\n// Access a specific material\nconst material = materials.value.MaterialName\n```\n\nThis makes it easier to manipulate specific parts of your model or apply materials programmatically.\n"
  },
  {
    "path": "docs/guide/loaders/use-progress.md",
    "content": "# useProgress\n\nA composable to convenience wrap `THREE.DefaultLoadingManager` and returns the progress of the loading assets into the scene.\n\nThis comes handy to show an HTML loading bar or a spinner while the assets are being loaded.\n\n## Usage\n\n```ts\nimport { useProgress } from '@tresjs/cientos'\n\nconst { hasFinishLoading, progress, items } = await useProgress()\n```\n\nThen you can use the `progress` value to show a loading bar or a spinner:\n\n```vue\n<template>\n  <Transition\n    name=\"fade-overlay\"\n    enter-active-class=\"opacity-1 transition-opacity duration-200\"\n    leave-active-class=\"opacity-0 transition-opacity duration-200\"\n  >\n    <div\n      v-show=\"!hasFinishLoading\"\n      class=\"absolute bg-grey-600 t-0 l-0 w-full h-full z-20 flex justify-center items-center text-black font-mono\"\n    >\n      <div class=\"w-200px\">\n        Loading... {{ progress }} %\n        <i class=\"i-ic-twotone-catching-pokemon animate-rotate-in\"></i>\n      </div>\n    </div>\n  </Transition>\n  <TresCanvas preset=\"realistic\">\n    <TresPerspectiveCamera :position=\"[11, 11, 11]\" />\n    <OrbitControls />\n    <Suspense>\n      <Environment\n        background\n        :files=\"environmentFiles\"\n        path=\"https://raw.githubusercontent.com/Tresjs/assets/main/textures/environmentMap\"\n      />\n    </Suspense>\n  </TresCanvas>\n</template>\n```\n\n:::warning\nThis component use top level await. Please check the [Suspense API](https://vuejs.org/guide/built-ins/suspense.html#suspense) for more info\n:::\n"
  },
  {
    "path": "docs/guide/loaders/use-svg.md",
    "content": "# useSVG\n\n<DocsDemo>\n  <SVGDemo />\n</DocsDemo>\n\nLoad and display SVG elements in your **TresJS** scene. This guide covers both the `useSVG` composable for advanced use cases and the `SVG` component for simple declarative rendering.\n\n## useSVG Composable\n\nThe `useSVG` composable provides direct access to processed SVG layers, giving you full control over the resulting geometries and materials.\n\n### Usage\n\n::: code-group\n```vue{2,6} [TheModel.vue]\n<script setup lang=\"ts\">\nimport { useSVG } from '@tresjs/cientos'\n\nconst svgPath = './logo.svg'\nconst { state, layers, isLoading, dispose } = useSVG(svgPath, {\n  skipFills: false,\n  fillMaterial: { transparent: true, opacity: 0.8 }\n})\n</script>\n\n<template>\n  <TresGroup v-if=\"!isLoading\">\n    <TresMesh\n      v-for=\"(layer, index) in layers\"\n      :key=\"`layer-${index}`\"\n      :geometry=\"layer.geometry\"\n      :render-order=\"index\"\n    >\n      <TresMeshBasicMaterial v-bind=\"layer.material\" />\n    </TresMesh>\n  </TresGroup>\n</template>\n```\n```vue [app.vue]\n<script setup lang=\"ts\">\nimport { OrbitControls } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport TheModel from './TheModel.vue'\n</script>\n\n<template>\n  <TresCanvas clear-color=\"#333\">\n    <TresPerspectiveCamera :position=\"[0, 2, 10]\" />\n    <OrbitControls />\n    <TheModel />\n    <TresAmbientLight />\n    <TresDirectionalLight />\n  </TresCanvas>\n</template>\n```\n\n:::\n\nThe `useSVG` composable provides direct access to processed SVG layers, giving you full control over how they're rendered. This is particularly useful when you need to:\n\n- Manually control layer rendering\n- Apply custom animations to individual layers\n- Access geometry data programmatically\n- Implement complex material logic\n\n### SVG Data Sources\n\nThe composable accepts both file paths and inline SVG strings:\n\n```ts\nimport { useSVG } from '@tresjs/cientos'\n\n// From file\nconst { layers } = useSVG('/path/to/file.svg')\n\n// Inline SVG string\nconst svgString = `<svg viewBox=\"0 0 100 100\">\n  <circle cx=\"50\" cy=\"50\" r=\"40\" fill=\"red\" />\n</svg>`\nconst { layers } = useSVG(svgString)\n```\n\n### Return Values\n\n| Name         | Type          | Description                                    |\n| :----------- | ------------- | ---------------------------------------------- |\n| **state**    | `SVGResult`   | The loaded SVG state from SVGLoader           |\n| **layers**   | `SVGLayer[]`  | Computed array of processed geometries and materials |\n| **isLoading**| `boolean`     | Whether the SVG is currently loading          |\n| **dispose**  | `() => void`  | Function to dispose of all geometries         |\n\n### Options\n\n| Name              | Type                                      | Default       | Description                          |\n| :---------------- | ----------------------------------------- | ------------- | ------------------------------------ |\n| **skipStrokes**   | `boolean`                                | `false`       | Whether to skip rendering strokes    |\n| **skipFills**     | `boolean`                                | `false`       | Whether to skip rendering fills      |\n| **fillMaterial**  | `MeshBasicMaterialParameters`            | `{}`          | Material properties for fill layers |\n| **strokeMaterial**| `MeshBasicMaterialParameters`            | `{}`          | Material properties for stroke layers |\n| **depth**         | `'renderOrder' \\| 'flat' \\| 'offsetZ' \\| number` | `'renderOrder'` | How layers should be rendered in 3D space |\n\n### Working with Layers\n\nThe `layers` computed property returns an array of processed SVG elements, each containing:\n\n```ts\ninterface SVGLayer {\n  geometry: BufferGeometry // Three.js geometry for the layer\n  material: MeshBasicMaterialParameters // Material properties\n  isStroke: boolean // Whether this layer is a stroke or fill\n}\n```\n\n#### Accessing Individual Layers\n\n```vue\n<script setup lang=\"ts\">\nimport { useSVG } from '@tresjs/cientos'\n\nconst { layers } = useSVG('/complex-icon.svg')\n\n// Apply different materials based on layer type\nconst getFillColor = (layer: SVGLayer, index: number) => {\n  return layer.isStroke ? '#000000' : `hsl(${index * 30}, 70%, 50%)`\n}\n</script>\n\n<template>\n  <TresGroup>\n    <TresMesh\n      v-for=\"(layer, index) in layers\"\n      :key=\"index\"\n      :geometry=\"layer.geometry\"\n    >\n      <TresMeshBasicMaterial\n        v-bind=\"layer.material\"\n        :color=\"getFillColor(layer, index)\"\n      />\n    </TresMesh>\n  </TresGroup>\n</template>\n```\n\n#### Custom Animation\n\n```vue\n<script setup lang=\"ts\">\nimport { useSVG } from '@tresjs/cientos'\nimport { useRenderLoop } from '@tresjs/core'\nimport { ref } from 'vue'\n\nconst { layers } = useSVG('/animated-logo.svg')\nconst rotation = ref(0)\n\nconst { onLoop } = useRenderLoop()\nonLoop(({ delta }) => {\n  rotation.value += delta\n})\n</script>\n\n<template>\n  <TresGroup>\n    <TresMesh\n      v-for=\"(layer, index) in layers\"\n      :key=\"index\"\n      :geometry=\"layer.geometry\"\n      :rotation-z=\"rotation * (index + 1) * 0.1\"\n    >\n      <TresMeshBasicMaterial v-bind=\"layer.material\" />\n    </TresMesh>\n  </TresGroup>\n</template>\n```\n\n### Depth Handling\n\nThe `depth` option controls how SVG layers are rendered in 3D space. It accepts the following values:\n\n#### `'renderOrder'` (Default)\n\n**Use case: Lone SVGs or applications that don't rely on stacked SVGs**\n\nThis is the default `depth` option.\n\nThis value sets the materials' `depthWrite` to `false` and increments the [mesh layers' `renderOrder`](https://threejs.org/docs/?q=mesh#api/en/core/Object3D.renderOrder). This makes the SVG layers render dependably regardless of perspective.\n\n**Disadvantage**: Scene objects may render out of order.\n\nSVG layers with higher `renderOrder` will be rendered after (i.e., sometimes \"on top of\") other objects in the scene graph with a lower `renderOrder`. Depending on their settings, those other objects may render behind the SVG, even if they are closer to the camera.\n\n```ts\nconst { layers } = useSVG('/icon.svg', { depth: 'renderOrder' })\n```\n\n#### `'flat'`\n\n**Use case: simple SVGs**\n\nThis option sets the [materials' `depthWrite`](https://threejs.org/docs/?q=mesh#api/en/materials/Material.depthWrite) to `false`.\n\n**Disadvantage**: SVG layers may render out of order.\n\nOverlapping layers in an SVG may be drawn out of order, depending on viewing perspective.\n\n```ts\nconst { layers } = useSVG('/icon.svg', { depth: 'flat' })\n```\n\n#### `'offsetZ'`\n\n**Use case: unscaled SVGs seen from the front**\n\nWhen this value is passed, the result is a 3D \"stack\" of mesh layers. A small space is added between each mesh layer in the \"stack\".\n\n**Disadvantage**: \"Bottom\" of the \"stack\" is visible; layers may z-fight.\n\nWhen seen from behind, the \"bottom\" of the mesh layer \"stack\" is visible. The space between the layers may be noticeable depending on viewing perspective and scale. The layers may [z-fight](https://en.wikipedia.org/wiki/Z-fighting), particularly if the SVG is scaled down.\n\n```ts\nconst { layers } = useSVG('/icon.svg', { depth: 'offsetZ' })\n```\n\n#### `number`\n\n**Use case: SVGs seen from the front**\n\nThis is the same as `'offsetZ'` but allows you to specify how much space is added between each layer, in order to eliminate [z-fighting](https://en.wikipedia.org/wiki/Z-fighting). For most use cases, this should be a value greater than 0.025 and less than 1.\n\n**Disadvantage**: \"Bottom\" of the \"stack\" is visible.\n\n```ts\nconst { layers } = useSVG('/icon.svg', { depth: 0.1 })\n```\n\n### Memory Management\n\nAlways dispose of geometries when the component unmounts:\n\n```vue\n<script setup lang=\"ts\">\nimport { useSVG } from '@tresjs/cientos'\nimport { onUnmounted } from 'vue'\n\nconst { dispose } = useSVG('/icon.svg')\n\nonUnmounted(() => {\n  dispose()\n})\n</script>\n```\n\n### Advanced Usage\n\n#### Conditional Layer Rendering\n\n```vue\n<script setup lang=\"ts\">\nimport { useSVG } from '@tresjs/cientos'\nimport { computed } from 'vue'\n\nconst showDetails = ref(true)\nconst { layers } = useSVG('/detailed-icon.svg')\n\nconst visibleLayers = computed(() =>\n  showDetails.value\n    ? layers.value\n    : layers.value.filter(layer => !layer.isStroke)\n)\n</script>\n\n<template>\n  <TresGroup>\n    <TresMesh\n      v-for=\"(layer, index) in visibleLayers\"\n      :key=\"index\"\n      :geometry=\"layer.geometry\"\n    >\n      <TresMeshBasicMaterial v-bind=\"layer.material\" />\n    </TresMesh>\n  </TresGroup>\n</template>\n```\n\n#### Material Customization per Layer\n\n```vue\n<script setup lang=\"ts\">\nimport { useSVG } from '@tresjs/cientos'\n\nconst { layers } = useSVG('/logo.svg', {\n  fillMaterial: {\n    transparent: true,\n    opacity: 0.9\n  },\n  strokeMaterial: {\n    transparent: true,\n    opacity: 1.0,\n    color: '#000000'\n  }\n})\n</script>\n\n<template>\n  <TresGroup>\n    <TresMesh\n      v-for=\"(layer, index) in layers\"\n      :key=\"index\"\n      :geometry=\"layer.geometry\"\n    >\n      <TresMeshBasicMaterial\n        v-bind=\"layer.material\"\n        :wireframe=\"layer.isStroke\"\n      />\n    </TresMesh>\n  </TresGroup>\n</template>\n```\n\n## UseSVG Component\n\nFor simple, declarative SVG rendering without the need for programmatic control, you can use the `SVG` component:\n\n```vue\n<script setup lang=\"ts\">\nimport { UseSVG } from '@tresjs/cientos'\n</script>\n\n<template>\n  <TresGroup :scale=\"0.01\" :position=\"[-2.1, 1, 0]\">\n    <UseSVG\n      src=\"/path/to/logo.svg\"\n      :skip-fills=\"false\"\n      :fill-material=\"{ transparent: true, opacity: 0.8 }\"\n      depth=\"renderOrder\"\n    />\n  </TresGroup>\n</template>\n```\n\n### Props\n\n| Prop                | Type                                             | Description                                                        | Default       |\n| :------------------ | -------------------------------------------------| :----------------------------------------------------------------- | ------------- |\n| **src**             | `string`                                         | Either a path to an SVG *or* an SVG string                         |               |\n| **skipStrokes**     | `boolean`                                        | If `true`, the SVG strokes will not be rendered.                   | `false`       |\n| **skipFills**       | `boolean`                                        | If `true`, the SVG fills will not be rendered.                     | `false`       |\n| **strokeMaterial**  | `MeshBasicMaterialParameters`                    | Props to assign to the stroke materials of the resulting meshes.   | `undefined`   |\n| **fillMaterial**    | `MeshBasicMaterialParameters`                    | Props to assign to the fill materials of the resulting meshes.     | `undefined`   |\n| **strokeMeshProps** | `TresOptions`                                    | Props to assign to the resulting stroke meshes.                    | `undefined`   |\n| **fillMeshProps**   | `TresOptions`                                    | Props to assign to the resulting fill meshes.                      | `undefined`   |\n| **depth**           | `'renderOrder' \\| 'flat' \\| 'offsetZ' \\| number` | Specify how SVG layers are to be rendered. ([See \"Depth\"](#depth-handling)) | `renderOrder` |\n\n## Troubleshooting\n\n::: warning\nThis is not a general-purpose SVG renderer. Many SVG features are unsupported.\n:::\n\nHere are some things to try if you run into problems:\n\n### Error: \"XML Parsing Error: unclosed token\"\n\n* In the SVG source, convert hex colors to rgb, e.g., convert `#ff0000` to `rgb(255, 0, 0)`.\n\n### Parts of the SVG render in the wrong order or disappear, depending on viewing angle\n\n* In your `useSVG` options, [change the `depth` option](#depth-handling).\n* In the SVG source, use `fill=\"none\"` rather than `fill-opacity=\"0\"`.\n\n### Parts of the SVG [\"z-fight\"](https://en.wikipedia.org/wiki/Z-fighting)\n\n* In your `useSVG` options, [change the `depth` option](#depth-handling).\n* Increase the distance between the SVG and other on-screen elements.\n\n### The SVG is not visible\n\n* If importing an SVG, make sure the path is correct – check the console for loading errors.\n* Try scaling the SVG down, e.g., wrap it in a `TresGroup` with `:scale=\"0.01\"`.\n* Try moving the SVG up (+y), e.g., `:position=\"[0,2,0]\"`.\n* Check that `layers.length > 0` before rendering.\n\n### Performance issues with many layers\n\n* Use the `dispose()` function when components unmount to clean up geometries.\n* Consider using `skipStrokes` or `skipFills` to reduce the number of rendered layers.\n* For complex SVGs with many layers, consider simplifying the SVG source.\n\n## When to Use `useSVG` vs `SVG` Component\n\n**Use `useSVG` when you need:**\n- Direct access to individual SVG layers\n- Custom rendering logic\n- Layer-specific animations\n- Programmatic geometry manipulation\n- Advanced material customization per layer\n\n**Use the `SVG` component when you need:**\n- Simple, declarative SVG rendering\n- Quick prototyping\n- Standard SVG display without custom logic\n- Less code and setup\n"
  },
  {
    "path": "docs/guide/loaders/use-texture.md",
    "content": "# useTexture\n\n<DocsDemo>\n  <UseTextureDemo />\n</DocsDemo>\n\nA composable that allows you to load textures using the [THREE.js texture loader](https://threejs.org/docs/#api/en/loaders/TextureLoader) into your **TresJS** scene.\n\n## Usage\n\n```vue [TexturedObject.vue]\n<script setup lang=\"ts\">\nimport { useTexture } from '@tresjs/cientos'\n\nconst { state: texture, isLoading, error } = useTexture(path)\n</script>\n\n<template>\n  <TresMesh>\n    <TresSphereGeometry />\n    <TresMeshStandardMaterial :map=\"texture\" />\n  </TresMesh>\n</template>\n```\n\n## Options\n\n| Name            | Type      | Default     | Description                          |\n| :-------------- | --------- | ----------- | ------------------------------------ |\n| **path**       | `string` | `undefined` | The path to the texture. |\n| **manager**    | `THREE.LoadingManager` | `undefined` | The loading manager to use for the texture. |\n\n## Component Usage\n\n```vue [UseTexture.vue]\n<script setup lang=\"ts\">\nimport { UseTexture } from '@tresjs/cientos'\n\nconst path = 'https://raw.githubusercontent.com/Tresjs/assets/main/textures/black-rock/Rock035_2K_Color.jpg'\n\nconst handleLoaded = (texture: Texture) => {\n  console.log('Loaded texture', texture)\n}\n\nconst handleError = (error: unknown) => {\n  console.error('error', error)\n}\n</script>\n\n<template>\n  <UseTexture\n    v-slot=\"{ state: texture }\"\n    :path=\"path\"\n    @loaded=\"handleLoaded\"\n    @error=\"handleError\"\n  >\n    <TresMesh>\n      <TresSphereGeometry />\n      <TresMeshStandardMaterial :map=\"texture\" />\n    </TresMesh>\n  </UseTexture>\n</template>\n```\n"
  },
  {
    "path": "docs/guide/loaders/use-textures.md",
    "content": "# useTextures\n\n<DocsDemo>\n  <PBRTexturesDemo />\n</DocsDemo>\n\nA composable that allows you to load multiple textures at once using the [THREE.js texture loader](https://threejs.org/docs/#api/en/loaders/TextureLoader) into your **TresJS** scene.\n\n## Usage\n\n```vue [TexturedObjects.vue]\n<script setup lang=\"ts\">\nimport { useTextures } from '@tresjs/cientos'\n\n// Define an array of texture paths\nconst texturePaths = [\n  '/textures/color.jpg',\n  '/textures/normal.jpg',\n  '/textures/roughness.jpg'\n]\n\n// Load all textures at once\nconst { textures, isLoading, error } = useTextures(texturePaths)\n</script>\n\n<template>\n  <TresMesh>\n    <TresSphereGeometry />\n    <TresMeshStandardMaterial\n      :map=\"textures[0]\"\n      :normal-map=\"textures[1]\"\n      :roughness-map=\"textures[2]\"\n    />\n  </TresMesh>\n</template>\n```\n\n## PBR Textures Example\n\nHere's a more advanced example showing how to load and apply PBR (Physically Based Rendering) textures to a material:\n\n```vue [PBRTextures.vue]\n<script setup lang=\"ts\">\nimport { TresCanvas, vLightHelper } from '@tresjs/core'\nimport { Environment, OrbitControls, useGLTF, useTextures } from '@tresjs/cientos'\nimport { MeshStandardMaterial } from 'three'\n\n// Load the 3D model\nconst { state: model } = useGLTF('/blender-cube-draco.glb', { draco: true })\nconst cube = computed(() => model.value?.nodes?.BlenderCube)\nconst material = computed(() => model.value?.materials?.Material)\n\n// Define texture paths\nconst texturePaths = [\n  '/textures/Metal053C_4K-JPG/Metal053C_4K-JPG_Color.jpg',\n  '/textures/Metal053C_4K-JPG/Metal053C_4K-JPG_NormalGL.jpg',\n  '/textures/Metal053C_4K-JPG/Metal053C_4K-JPG_Roughness.jpg',\n  '/textures/Metal053C_4K-JPG/Metal053C_4K-JPG_Metalness.jpg',\n  '/textures/Metal053C_4K-JPG/Metal053C_4K-JPG_Displacement.jpg'\n]\n\n// Load all PBR textures at once\nconst { textures, isLoading, error } = useTextures(texturePaths)\n\n// Apply textures to material when loaded\nwatch([material, textures], ([modelMaterial, textures]) => {\n  if (modelMaterial && textures && textures.length === texturePaths.length) {\n    // Cast to MeshStandardMaterial to access PBR properties\n    const pbrMaterial = modelMaterial as MeshStandardMaterial\n\n    // Apply textures\n    pbrMaterial.map = textures[0]\n    pbrMaterial.normalMap = textures[1]\n    pbrMaterial.roughnessMap = textures[2]\n    pbrMaterial.metalnessMap = textures[3]\n    pbrMaterial.displacementMap = textures[4]\n\n    // Set material properties\n    pbrMaterial.displacementScale = 0\n    pbrMaterial.metalness = 0.8\n    pbrMaterial.roughness = 0.2\n  }\n})\n\n// Handle loading state and errors\nwatch(isLoading, (_loading) => {\n  // Handle loading state\n})\n\nwatch(error, (errs) => {\n  if (errs) {\n    console.error('Error loading textures:', errs)\n  }\n})\n</script>\n\n<template>\n  <TresCanvas clear-color=\"#4f4f4f\">\n    <Suspense>\n      <Environment preset=\"studio\" background :blur=\"1\" />\n    </Suspense>\n    <TresPerspectiveCamera :position=\"[8, 8, 8]\" />\n    <OrbitControls />\n    <TresGridHelper />\n    <TresAmbientLight :intensity=\"2\" />\n    <TresDirectionalLight v-light-helper :position=\"[5, 5, 5]\" :intensity=\"0.5\" color=\"#ff0000\" />\n    <TresDirectionalLight v-light-helper :position=\"[-5, 2, 2]\" :intensity=\"0.5\" color=\"#0000ff\" />\n    <TresGroup position-y=\"2\">\n      <primitive v-if=\"cube\" :object=\"cube\" />\n    </TresGroup>\n  </TresCanvas>\n</template>\n```\n\n## API\n\n### Parameters\n\n| Name            | Type      | Default     | Description                          |\n| :-------------- | --------- | ----------- | ------------------------------------ |\n| **paths**       | `string[]` | `undefined` | Array of paths to the textures. |\n\n### Returns\n\n| Name            | Type      | Description                          |\n| :-------------- | --------- | ------------------------------------ |\n| **textures**    | `Texture[]` | Array of loaded textures. |\n| **isLoading**   | `boolean` | Whether any textures are still loading. |\n| **error**       | `Error[] \\| null` | Array of errors if any occurred during loading. |\n\n## Benefits\n\n- **Simplified API**: Load multiple textures with a single function call\n- **Consolidated loading state**: Track loading state for all textures at once\n- **Unified error handling**: Collect and report errors from all texture loads\n- **Type safety**: Proper TypeScript typing throughout the implementation\n"
  },
  {
    "path": "docs/guide/loaders/use-video-texture.md",
    "content": "# useVideoTexture <Badge type=\"warning\" text=\"^3.2.0\" />\n\n<DocsDemo>\n  <VideoTextureDemo />\n</DocsDemo>\n\nA composable to easily use videos as textures in your meshes.\n\nThis composable is based on the Drei [useVideoTexture](https://github.com/pmndrs/drei/tree/master#usevideotexture)\n\n## Usage\n\n::: code-group\n```vue [app.vue]\n<script setup lang=\"ts\">\nimport { OrbitControls } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport TheModel from './TheModel.vue'\n</script>\n\n<template>\n  <TresCanvas clear-color=\"#333\">\n    <TresPerspectiveCamera\n      :position=\"[0, 5, 9]\"\n      :look-at=\"[0, 1, 0]\"\n    />\n    <OrbitControls />\n    <Suspense>\n      <TheModel />\n    </Suspense>\n    <TresGridHelper />\n    <TresAmbientLight />\n  </TresCanvas>\n</template>\n```\n```vue{3,8,13} [TheVideoTexture.vue]\n<script setup lang=\"ts\">\nimport { ref } from 'vue'\nimport { Sphere, useVideoTexture } from '@tresjs/cientos'\n\nconst videoPath = 'https://raw.githubusercontent.com/'\n  + 'Tresjs/assets/main/textures/video-textures/useVideoTexture.mp4'\nconst texture = ref()\ntexture.value = await useVideoTexture(videoPath, { loop: false })\n</script>\n\n<template>\n   <Sphere :position=\"[0, 2, 0]\">\n      <TresMeshBasicMaterial :map=\"texture\" />\n    </Sphere>\n</template>\n```\n:::\n\n## Props\n\n| Prop          | Description                                                              | Default          |\n| :------------ | :----------------------------------------------------------------------- | ---------------- |\n| `src`         | Path to the video.                                                       | `undefined`      |\n| `unsuspend`   | Path to the model file.                                                  | `loadedmetadata` |\n| `crossOrigin` | Whether to use CORS to fetch the related video.                          | `Anonymous`      |\n| `muted`       | Whether to set the audio silenced.                                       | true             |\n| `loop`        | Automatically seek back to the start upon reaching the end of the video. | true             |\n| `start`       | To play to the video once loaded or not.                                 | true             |\n| `playsInline` | To be play the video inline or not.                                      | true             |\n\n- Any other attribute for a `<video>` tag is accepted and will automatically set\n"
  },
  {
    "path": "docs/guide/materials/custom-shader-material.md",
    "content": "# TresCustomShaderMaterial <Badge type=\"warning\" text=\"^3.6.0\" />\n\n<DocsDemo>\n  <CustomShaderMaterialDemo />\n</DocsDemo>\n\nThe `cientos` package provides a new `<TresCustomShaderMaterial />` component which is a wrapper around the [`three-custom-shader-material`](https://github.com/FarazzShaikh/THREE-CustomShaderMaterial) class. As states in the repo, it _\"lets you extend Three.js' material library with your own Vertex and Fragment shaders\"_.\n\n## Usage\n\n<<< @/.vitepress/theme/components/CustomShaderMaterialDemo.vue{3,7,16-49,55-56,97}\n\n## Props\n\nBeing a wrapper around the `CustomShaderMaterial` class, the `<TresCustomShaderMaterial />` component accepts all the props that the class does. You can find the full list of props in the [official repo](https://github.com/FarazzShaikh/THREE-CustomShaderMaterial).\n"
  },
  {
    "path": "docs/guide/materials/glass-material.md",
    "content": "# MeshGlassMaterial <Badge type=\"warning\" text=\"^3.2.0\" />\n\n<DocsDemo>\n  <GlassMaterialDemo />\n</DocsDemo>\n\nThe `cientos` package provides a new`<MeshGlassMaterial />` component that makes a geometry look like glass. This is achieved by re-defining the `MeshPhysicalMaterial` so all the default props can be passed normally.\n\n## Usage\n\n### You can use it like you normally do with TresJs\n\n<<< @/.vitepress/theme/components/GlassMaterialDemo.vue{3,9-12}\n\n### You can also replace the material of an existing mesh like this:\n\n```vue{4,6-15,20}\n<script setup lang=\"ts\">\nimport { ref, shallowRef, watch } from 'vue'\nimport { TresCanvas } from '@tresjs/core'\nimport { MeshGlassMaterial, Box } from '@tresjs/cientos'\n\nconst glassMaterialRef = shallowRef()\nconst boxRef = shallowRef()\n\nwatch(glassMaterialRef, value => {\n  // For good practice we dispose the old material\n  boxRef.value.instance.material.dispose()\n\n  // We assign the new MeshGlassMaterialClass\n  boxRef.value.instance.material = value.MeshGlassMaterialClass\n})\n</script>\n<template>\n  <TresMesh>\n    <TresTorusGeometry />\n    <MeshGlassMaterial ref=\"glassMaterialRef\" />\n  </TresMesh>\n  <!-- Mesh to be replaced -->\n  <TresMesh ref=\"boxRef\">\n    <TresBoxGeometry />\n    <MeshBasicMaterial  />\n  </TresMesh>\n</template>\n```\n## Tips\n\nFor more fine tuning effects you can provide an environment map texture as an envMap and play with the intensity to achieve a more realistic effect\n\nAlso, another good option is to provide a normal texture as clearcoatNormalMap to add different results\n\nYou can find more information in the official [ThreeJs docs](https://threejs.org/docs/index.html?q=phys#api/en/materials/MeshPhysicalMaterial).\nYou can play with this [example](https://playground.tresjs.org/experiments/glass-material) and be inspired.\nAlso worth checking is this [blog](https://tympanus.net/codrops/2021/10/27/creating-the-effect-of-transparent-glass-and-plastic-in-three-js/)\n"
  },
  {
    "path": "docs/guide/materials/holographic-material.md",
    "content": "# HolographicMaterial\n\n<DocsDemo>\n  <HolographicMaterialDemo />\n</DocsDemo>\n\n## A simple to use holographic material for TresJS\n\nDive into a world of mesmerizing holographic wonders with the HolographicMaterial for vanilla three.js. This enchanting three.js material brings your virtual reality experiences to life, infusing them with a burst of vibrant colors, dynamic scanlines, and a touch of futuristic brilliance.\n\nWhile this material operates independently of any post-processing, it achieves an enhanced visual appeal when coupled with bloom effects. The utilization of bloom proves particularly effective in rendering a captivating glow effect, especially in areas where overexposure is prevalent.\n\n:::info\nThis component ports Anderson Mancini's [threejs-vanilla-holographic-material](https://github.com/ektogamat/threejs-vanilla-holographic-material) to TresJS. All credit goes to him.\n:::\n\n## Usage\n\n```vue{3,10}\n<script setup lang=\"ts\">\nimport { TresCanvas } from '@tresjs/core'\nimport { HolographicMaterial, Sphere } from '@tresjs/cientos'\n\n</script>\n<template>\n  <TresCanvas>\n    <TresPerspectiveCamera :position=\"[3, 3, 3]\" />\n    <Sphere :scale=\"0.5\">\n      <HolographicMaterial />\n    </Sphere>\n    <TresAmbientLight />\n  </TresCanvas>\n</template>\n```\n\n### Replace a mesh's material\n\nYou can also replace the material of an existing mesh like this:\n\n<<< @/.vitepress/theme/components/HolographicMaterialDemo.vue{4}\n\n## Props\n\n| Prop                   | Description                                                   | Type                                                | default   |\n| :--------------------- | :------------------------------------------------------------ | --------------------------------------------------- | --------- |\n| **fresnelAmount**      | Value of the Fresnel effect. Ranges from 0.0 to 1.0.          | `Number`                                            | `0.45`    |\n| **fresnelOpacity**     | Opacity of the Fresnel effect. Ranges from 0.0 to 1.0.        | `Number`                                            | `1.0`    |\n| **scanlineSize**       | Size of the scanlines. Ranges from 1 to 15.                   | `Number`                                            | `8.0`       |\n| **hologramBrightness** | Brightness of the hologram. Ranges from 0.0 to 2.0.           | `Number`                                            | `1.2`       |\n| **signalSpeed**        | Speed of the signal effect. Ranges from 0.0 to 2.0.           | `Number`                                            | `0.45`      |\n| **hologramColor**      | Specifies the color of the hologram.                          | `String`                                            | `\"#00d5ff\"` |\n| **enableBlinking**     | Enables or disables the blinking effect.                      | `Boolean`                                           | `true`      |\n| **hologramOpacity**    | Specifies the opacity of the hologram.                        | `Number`                                            | `1.0`       |\n| **blinkFresnelOnly**   | Enables or disables the blinking effect for the Fresnel only. | `Boolean`                                           | `true`      |\n| **enableAdditive**     | Enables or disables the Additive Blend Mode.                  | `Boolean`                                           | `true`      |\n| **side**               | Specifies side for the material, as String.                   | `THREE.FrontSide, THREE.BackSide, THREE.DoubleSide` | `FrontSide` |\n"
  },
  {
    "path": "docs/guide/materials/mesh-discard-material.md",
    "content": "# MeshDiscardMaterial\n\n`<MeshDiscardMaterial />` hides the object it's attached to. The object's shadows and children will be rendered.\n\n## Usage\n\n```vue\n<script setup lang=\"ts\">\nimport { TresCanvas } from '@tresjs/core'\nimport { MeshDiscardMaterial } from '@tresjs/cientos'\n</script>\n\n<template>\n  <TresCanvas>\n    <TresPerspectiveCamera />\n    <TresMesh>\n      <TresBoxGeometry />\n      <MeshDiscardMaterial />\n    </TresMesh>\n  </TresCanvas>\n</template>\n```\n"
  },
  {
    "path": "docs/guide/materials/mesh-reflection-material.md",
    "content": "# MeshReflectionMaterial\n\n<DocsDemo>\n  <MeshReflectionMaterialDemo />\n</DocsDemo>\n\nThe `cientos` package provides a `<MeshReflectionMaterial />` component for making floors or walls that reflect the objects in your `Scene`.\n\nThe component is based on the excellent [Drei](https://github.com/pmndrs/drei) component of the same name.\n\nIt extends `THREE.MeshStandardMaterial` and accepts all the same props.\n\n## Usage\n\n<<< @/.vitepress/theme/components/MeshReflectionMaterialDemo.vue{3,16-19}\n\n## Props\n\nNo props are required.\n\n<CientosPropsTable\n:fields=\"['name', 'description', 'default']\"\n:on-format-value=\"({value, fieldName, valueFormatted, getFieldFormatted}) => {\n  if (fieldName === 'description') {\n    const t = getFieldFormatted('type')\n    return t ? t + value : value\n  }\n}\"\ncomponent-path=\"src/core/materials/meshReflectionMaterial/index.vue\" />\n"
  },
  {
    "path": "docs/guide/materials/point-material.md",
    "content": "# PointMaterial\n\n<DocsDemo>\n  <PointMaterialDemo />\n</DocsDemo>\n\n`<PointMaterial />` extends `THREE.PointsMaterial`. It renders the points as dots, rather than the default squares.\n\n::: info\nN.B., stacking order and transparency of objects using `THREE.PointsMaterial` and by extension `<PointMaterial />` can be somewhat unintuitive, especially when combined with other on-screen objects. [Please see discussions at threejs.org for more infomation.](https://discourse.threejs.org/search?q=points%20transparency)\n:::\n\n## Usage\n\n<<< @/.vitepress/theme/components/PointMaterialDemo.vue\n\n## Props\n\nAll [`THREE.PointsMaterial` properties](https://threejs.org/docs/#api/en/materials/PointsMaterial) are inherited by `PointMaterial`.\n"
  },
  {
    "path": "docs/guide/materials/wobble-material.md",
    "content": "# MeshWobbleMaterial\n\n<DocsDemo>\n  <WobbleMaterialDemo />\n</DocsDemo>\n\nThe `cientos` package provides a `<MeshWobbleMaterial />` component that makes a geometry wobble and wave around. This material extends `MeshStandardMaterial` so all the default props can be passed as well in addition for two more:\n\n- `speed` how fast the wobble effect would be\n- `factor`: how strong the wobble effect will deform the geometry\n\n## Usage\n\n<<< @/.vitepress/theme/components/WobbleMaterialDemo.vue{3,11-15}\n"
  },
  {
    "path": "docs/guide/migrating-from-v3.md",
    "content": "# Migration Guide from v3\n\nThis guide is intended to help you migrate from Cientos v3 to v4 🤩✨.\n\n::: code-group\n\n```bash [pnpm]\npnpm update @tresjs/cientos\n```\n\n```bash [npm]\nnpm update @tresjs/cientos\n```\n\n```bash [yarn]\nyarn upgrade @tresjs/cientos\n```\n\n:::\n\n## What's new?\n\n### Updated `defineExport` properties\n\nSince the beginning we exported our components' underlying `Three.js` instances using the name `value`. This created a very ambiguos situation with some components. When we access them using a `ref` in `<template>`, we ended up with something like:\n\n```vue{6}\n<script>\nimport { shallowRef, watch } from 'vue'\nimport { TresCanvas } from '@tresjs/core'\nimport { Stars } from '@tresjs/cientos'\n\nconst starsRef = shallowRef()\n\nwatch(starsRef, () => {\n  // to access the instance we have a nested `value.value`\n  console.log(starsRef.value.value)\n  // Wrong in v4 ❌\n})\n</script>\n<template>\n  <TresCanvas>\n    ...\n    <Stars ref=\"starsRef\" />\n    ...\n  </TresCanvas>\n</template>\n```\n\nThis created confusion and was not good DX. Unfortunately, to fix this, a breaking change needed to be introduced, and we felt this was the right moment.\n\nThe new implementation is very similar, but instead of two confusing `value`s we have standardized all our components with `instance`, so to access the components now use:\n\n```js\n// Correct in v4 ✅\nconsole.log(starsRef.value.instance)\n```\n\n### Remove `TweakPane` from deps\n\nAfter some iteration, we decided to drop the instance of `useTweakPane`. Some of the reasons are:\n\n- No compatibility with the v4 of [TweakPane](https://tweakpane.github.io/docs/)\n- Massive bundle size\n- Not so intuitive, lots of code repetition\n- Support for the upcoming pkg [Leches](https://tresleches.tresjs.org/)\n\nYou can check this recipe on the tres docs on how to use tweakpane with tres: [TweakPane](https://docs.tresjs.org/cookbook/tweakpane.html)\n\n### Move directives to core\n\nThe use of `directives` started as a experiment to see how valuable it would be for the ecosystem. Since it has had a good reception, we have decided that it is appropriate for the `directives` to live under the core pkg [Directives section](https://docs.tresjs.org/directives/v-log.html).\n\nSo now you have to import your directives from the core:\n```ts\n// Correct ✅\nimport { vLog } from '@tresjs/core'\n```\n\nInstead of:\n```ts\n// Wrong ❌\nimport { vLog } from '@tresjs/cientos'\n```\n\n::: info\nSince the addition of the new `useLoop` method, `vAlwaysLookAt` and `vRotate` have been temporarily removed.\n:::\n\n### Changes in `KeyboardControls`\n\nThe implementation of `KeyboardControls` has been changed, since this component doesn't provide the right setup for what was originally developed. We took the decision to adopt floating controls similar to Unreal Engine 5, which make more sense given the name of this component.\n\nWe have also brought the `PointerLockControls` inside `KeyboardControls`, so you don't have to set it up manually.\n\nLearn more about it [here](https://cientos.tresjs.org/guide/controls/keyboard-controls.html).\n"
  },
  {
    "path": "docs/guide/misc/bake-shadows.md",
    "content": "# BakeShadows\n\n<DocsDemo>\n  <BakeShadowsDemo />\n</DocsDemo>\n\n**Cientos** provides a component called `BakeShadows`. Basically this component set the renderer.shadowMap.autoUpdate to `false`, so the shadows are casted just in the first frame which is really great for performance, the downside of this method is that the shadows will not be updated.\n\n## Basic usage\n\n::: warning\nYou have to set the shadows in the `TresCanvas` (renderer), your light sources and objects to receive and cast accordantly as you normally would do.\n:::\n"
  },
  {
    "path": "docs/guide/misc/html-component.md",
    "content": "# Html <Badge type=\"warning\" text=\"^3.5.0\" />\n\nThis component allows you to project HTML content to any object in your scene. TresJS will automatically update the position of the HTML content to match the position of the object in the scene.\n\n<DocsDemo>\n  <HtmlDemo />\n</DocsDemo>\n\n## Usage\n\n<<< @/.vitepress/theme/components/HtmlDemo.vue{2,18-28}\n\n## Occlusion\n\nBy default, the HTML content will be visible through other objects in the scene. You can use the `occlude` prop to make the HTML content occlude other objects in the scene.\n\nHtml can hide behind geometry using the occlude prop.\n\n```\n<Html occlude>\n```\n\nYou can also choose which objects should occlude the HTML content by passing an array of objects refs to the `occlude` prop.\n\n<DocsDemo>\n  <HtmlOccludeDemo />\n</DocsDemo>\n\n<<< @/.vitepress/theme/components/HtmlOccludeDemo.vue{2,11,24,33}\n\n## Using `iframes`\n\nYou can achieve pretty cool results with the `Html` component by using iframes. For example, you can use an iframe to display a YouTube video in your scene or a webpage with a 3D model.\n\n<DocsDemo>\n  <HtmlLaptopDemo />\n</DocsDemo>\n\n<<< @/.vitepress/theme/components/HtmlLaptopDemo.vue\n\n## Props\n\n| Prop                | Description                                                                                                               | Default                                  |\n|---------------------|---------------------------------------------------------------------------------------------------------------------------|------------------------------------------|\n| **as**              | Wrapping html element.                                                                                                    | `'div'`                                  |\n| **wrapperClass**    | The className of the wrapping element.                                                                                    |                                          |\n| **prepend**         | Project content behind the canvas.                                                                                        | `false`                                  |\n| **center**          | Adds a -50%/-50% CSS transform. [Ignored in transform mode]                                                               | `false`                                  |\n| **fullscreen**      | Aligns to the upper-left corner, fills the screen. [Ignored in transform mode]                                            | `false`                                  |\n| **distanceFactor**  | Children will be scaled by this factor, and also by distance to a PerspectiveCamera / zoom by an OrthographicCamera.      |                                          |\n| **zIndexRange**     | Z-order range.                                                                                                            | `[16777271, 0]`                          |\n| **portal**          | Reference to target container.                                                                                            |                                          |\n| **transform**       | If true, applies matrix3d transformations.                                                                                | `false`                                  |\n| **sprite**          | Renders as sprite, but only in transform mode.                                                                            | `false`                                  |\n| **calculatePosition** | Override default positioning function. [Ignored in transform mode]                                                      |                                          |\n| **occlude**         | Can be `true`, `Ref<TresObject3D>[]`, `'raycast'`, or `'blending'`. True occludes the entire scene.                       |                                          |\n| **geometry**         | Custom `geometry` to be use                                                                                              |                    `PlaneGeometry`       |\n| **material**         | Custom shader `material` to be use                                                                                              |                                          |\n\n## Events\n\n| Event               | Description                                                                                                               |\n|---------------------|---------------------------------------------------------------------------------------------------------------------------|\n| onOcclude           | Called when the occlusion state changes.                                                                                  |\n"
  },
  {
    "path": "docs/guide/misc/lod.md",
    "content": "# LOD\n\nLevel of Detail - show meshes with more or less geometry based on distance from the camera.\n\n`<LOD />` is a wrapper for THREE's [LOD](https://threejs.org/docs/?q=LOD#api/en/objects/LOD) class.\n\n<DocsDemo>\n  <LODDemo />\n</DocsDemo>\n\n## Usage\n<<< @/.vitepress/theme/components/LODDemo.vue\n\n## Props\n\n| Prop               | Description                                                            | Default |\n| :----------------- | :--------------------------------------------------------------------- | ------- |\n| **levels**           |  `number[]` - The distances at which to display each level of detail. There should be one `levels` value for each `LOD` child. |         |\n| **hysteresis**           | Threshold used to avoid flickering at LOD boundaries, as a fraction of distance. | `0.0` |\n"
  },
  {
    "path": "docs/guide/misc/stats-gl.md",
    "content": "# StatsGl\n\n[stats-gl](https://github.com/RenaudRohlinger/stats-gl) is a powerful WebGL performance monitoring tool created by [RenaudRohlinger](https://github.com/RenaudRohlinger).\nIt offers simple information boxes to track code performance and serves as a more advanced alternative to [stats.js](https://github.com/mrdoob/stats.js/), capable of displaying CPU and GPU metrics.\n\nIn TresJS, you can effortlessly create a performance monitoring panel in the top left corner of your canvas by using the StatsGl component.\nSimply drop the StatsGl component into your TresCanvas for easy performance monitoring.\n\n## Basic usage\n\n```vue{3,8}\n<script setup lang=\"ts\">\nimport { TresCanvas } from '@tresjs/core'\nimport { StatsGl } from '@tresjs/cientos'\n</script>\n\n<template>\n  <TresCanvas>\n    <StatsGl />\n  </TresCanvas>\n</template>\n```\n\n## Options\n\n| Name              | Type      | Default | Description                                          |\n| :---------------- | --------- | ------- | ---------------------------------------------------- |\n| **logsPerSecond** | `number`  | `20`    | How often to log performance data, in logs per second. |\n| **samplesLog**    | `number`  | `100`   | Number of recent log samples to keep for computing averages. |\n| **samplesGraph**  | `number`  | `10`    | Number of recent graph samples to keep for computing averages. |\n| **precision**     | `number`  | `2`     | Precision of the data, in the number of decimal places (only affects CPU and GPU). |\n| **horizontal**    | `boolean` | `true`  | Display the canvases on the X-axis, set to align on the vertical axis. |\n| **minimal**       | `boolean` | `false` | A boolean value to control the minimalistic mode of the panel display. If set to true, a simple click on the panel will switch between different metrics. |\n| **mode**          | `number`  | `0`     | Sets the initial panel to display - 0 for FPS, 1 for CPU, and 2 for GPU (if supported). |\n"
  },
  {
    "path": "docs/guide/misc/stats.md",
    "content": "# Stats\n\n[stats.js](https://github.com/mrdoob/stats.js/) is a JavaScript performance monitor, made by [mrdoob](https://github.com/mrdoob). stats.js provides a simple info box that will help you monitor your code performance.\n\n**Cientos** provides a component called `Stats` that creates a panel without effort or configuration in the top left corner where you'll be able to monitor your app.\n\n## Basic usage\n\n```vue{3,8}\n<script setup lang=\"ts\">\nimport { TresCanvas } from '@tresjs/core'\nimport { Stats } from '@tresjs/cientos'\n</script>\n\n<template>\n  <TresCanvas>\n    <Stats />\n  </TresCanvas>\n</template>\n```\n\n## Props\n\n| Prop          | Type     | Default | Description  |\n| :------------ | -------- | ------- | ------------ |\n| **showPanel** | `number` | `0`     | FPS monitor. |\n\n- 0: FPS Frames rendered in the last second. The higher the number the better.\n- 1: MS Milliseconds needed to render a frame. The lower the number the better.\n- 2: MB MBytes of allocated memory. (Run Chrome with --enable-precise-memory-info)\n- 3+: CUSTOM User-defined panel support. For more info please check [stats.js](https://github.com/mrdoob/stats.js/).\n"
  },
  {
    "path": "docs/guide/misc/use-gltf-exporter.md",
    "content": "# useGLTFExporter\n\n[GLTFExporter](https://threejs.org/docs/index.html?q=expo#examples/en/exporters/GLTFExporter) is an addon in threeJs that allows you to download any object3D in a [GLTF](https://www.khronos.org/gltf) format. **TresJS** provides a composable that simplifies this process with just a few lines of code.\n\n## Basic usage\n\n```vue{3,6,10,20}\n<script setup lang=\"ts\">\nimport { TresCanvas } from '@tresjs/core'\nimport { useGLTFExporter } from '@tresjs/cientos'\nimport { shallowRef } from 'vue'\n\nconst boxRef = shallowRef()\n\n// the second argument – options – is not required\nconst downloadBox = () => {\n  useGLTFExporter(boxRef.value, { fileName: 'cube', binary: true })\n}\n</script>\n<template>\n  <TresCanvas clear-color=\"#82DBC5\" window-size >\n    <TresPerspectiveCamera :position=\"[0, 2, 5]\" />\n    <TresMesh\n      ref=\"boxRef\"\n      :position-z=\"30\"\n      :scale=\"10\"\n      @click=\"downloadBox\"\n    >\n      <TresBoxGeometry :args=\"[1, 1, 1]\" />\n      <TresMeshStandardMaterial :color=\"0x00ff00\" />\n    </TresMesh>\n    <TresDirectionalLight :position=\"[0, 10, 10]\" />\n  </TresCanvas>\n</template>\n\n```\n\n### Download the scene: a quick tip\n\nIn the previous example, if we want to download the whole scene, we can easily do it by just accessing the `parent` property.\n```ts{3}\n...\nconst downloadBox = () => {\n  useGLTFExporter(boxRef.value.parent) // As the parent is the current scene\n}\n...\n```\n_This may vary in your scene please first check what is in your `parent` property_\n\nOtherwise, you can access your scene using the [useTresContext](https://docs.tresjs.org/api/composables.html#usetrescontext)\n\n## Arguments\n\n| Name         | Type       | Default     | Description                                          |\n| :----------- | ---------- | ----------- | ---------------------------------------------------- |\n| **Selector** | `Object3D` | Required    | The object to download. Could be an array of objects |\n| **Options**  | `Options`  | `undefined` | Description below                                    |\n\n## Options\n\n| Name                        | Type                   | Default       | Description                                                                 |\n| :-------------------------- | ---------------------- | ------------- | --------------------------------------------------------------------------- |\n| **trs**                     | `bool`                 | `false`       | Export position, rotation and scale instead of matrix per node              |\n| **onlyVisible**             | `bool`                 | `true`        | Export only visible objects                                                 |\n| **binary**                  | `bool`                 | `false`       | Export in binary (.glb) format, returning an ArrayBuffer                    |\n| **maxTextureSize**          | `number`               | `Infinity`    | Restricts the image maximum size (both width and height) to the given value |\n| **animations**              | `Array<AnimationClip>` | `undefined`   | List of animations to be included in the export                             |\n| **includeCustomExtensions** | `bool`                 | `Infinity`    | Export custom glTF extensions defined on an object's                        |\n| **fileName**                | `string`               | `Object name` | name of the generated fil                                                   |\n"
  },
  {
    "path": "docs/guide/misc/use-intersect.md",
    "content": "# useIntersect\n\n`useIntersect` is a function that returns `intersect`, a `Ref<boolean>` that's updated when the observed object enters or leaves the screen. This relies on [THREE.Object3D.onBeforeRender](https://threejs.org/docs/#api/en/core/Object3D.onBeforeRender) so it only works on objects that are effectively rendered, like meshes, lines, sprites. It won't work on other types like group, object3d, bone, etc.\n\n## Usage\n\n::: warning\n`useIntersect` requires a `TresCanvas` context, so it is only available in `TresCanvas` descendant components' `<script setup>`.\n:::\n\n```vue\n<script setup lang=\"ts\">\nimport { Torus, useIntersect } from '@tresjs/cientos'\n\nconst { ref, intersect, off } = useIntersect()\n</script>\n\n<template>\n  <Torus ref=\"ref\">\n    <TresMeshNormalMaterial />\n  </Torus>\n</template>\n```\n\n## Arguments\n\n| Name         | Description |  Type       |\n| :----------- | ----------- | ----------- |\n| **onChange** | Optional callback function triggered when the observed object enters or leaves the screen. | `(isIntersected: boolean) => void` |\n\n## Return\n\n| Name         | Description |  Type       |\n| :----------- | ----------- | ----------- |\n| **ref** | Vue `ShallowRef` to pass to the object to be observed. | `ShallowRef<Object3D>` |\n| **intersects** | Updates when the observed object's intersect status changes. | `ShallowRef<boolean>` |\n| **off** | Calling this function stops `useIntersect` until `ref` changes. | `() => void` |\n"
  },
  {
    "path": "docs/guide/shapes/box.md",
    "content": "# Box <Badge type=\"warning\" text=\"^1.6.0\" />\n\n![](/cientos/box.png)\n\nThe `cientos` package provides a `<Box />` component that serves as a short-cut for a `BoxGeometry` and a `MeshBasicMaterial` with a `Mesh` object.\n\n```\nargs: [\n  width: number,\n  height: number,\n  depth: number,\n  widthSegments: number,\n  heightSegments: number,\n  depthSegments: number\n]\n```\n\nReference: [BoxGeometry](https://threejs.org/docs/?q=box#api/en/geometries/BoxGeometry)\n\n## Usage\n\n```vue\n<Box :args=\"[1, 1, 1]\" color=\"orange\" />\n\n// Box with a custom material transformations\n<Box ref=\"boxRef\" :args=\"[1, 1, 1]\" :position=\"[0, 4, 0]\">\n  <TresMeshToonMaterial color=\"orange\" />\n</Box>\n```\n"
  },
  {
    "path": "docs/guide/shapes/catmullromcurve3.md",
    "content": "# CatmullRomCurve3\n\n<DocsDemo>\n  <CatmullRomCurve3Demo />\n</DocsDemo>\n\nThe `cientos` package provides a `<CatmullRomCurve3 />` component that allows you to make smooth(ish) 3D lines.\n\n`<CatmullRomCurve3 />` wraps [Three.js's `CatmullRomCurve3`](https://threejs.org/docs/index.html?q=catmu#api/en/extras/curves/CatmullRomCurve3) functionality, but applies it to Cientos' `<Line2 />` under the hood, meaning you can use [all the props from `<Line2 />`.](line2#props)\n\n## Usage\n<<< @/.vitepress/theme/components/CatmullRomCurve3Demo.vue{3,8-13}\n\n## Props\n\n| Prop         | Type      | Description                                                                   | Default        |\n| ------------ | --------- | ----------------------------------------------------------------------------- | -------------- |\n| points  | `Array<Vector3 \\| [number, number, number]>` | Curve's control points |            |\n| segments     | `number`  | Number of segments in the resulting curve (higher = smoother) | 20             |\n| closed       | `boolean` | The curve will loop back onto itself when this is true.                       | false          |\n| curveType    | `'centripetal' \\| 'chordal' \\| 'catmullrom'` | Curve type                                 | 'centripetal'  |\n| tension      | `number`  | Catmullrom's tension, when curveType is 'catmullrom'                          | 0.5            |\n| vertexColors    | `TresColor[]`            | Vertex colors, if using                                                    | null           |\n| color           | `TresColor`              | Color for the line – multiplies vertex colors                              | 'white'        |\n| lineWidth       | `number`                 | Width of the line – in world units with size attenuation, pixels otherwise | 1              |\n| worldUnits      | `boolean`                | Whether the line width is in world units or pixels                         | false          |\n| alphaToCoverage | `boolean`                | Enables alpha to coverage. Can only be used with MSAA-enabled contexts (meaning when the renderer was created with antialias parameter set to true).                                                               | false          |\n| dashed          | `boolean`                | Whether the line is dashed                                                 | false          |\n| dashSize        | `number`                 | Dash size                                                                  | 1              |\n| gapSize         | `number`                 | Gap size in dashed line                                                    | 1              |\n| dashScale       | `number`                 | Scale of the dashes/gaps                                                   | 1              |\n| dashOffset      | `number`                 | Dash offset                                                                | 0              |\n"
  },
  {
    "path": "docs/guide/shapes/circle.md",
    "content": "# Circle <Badge type=\"warning\" text=\"^1.6.0\" />\n\n![](/cientos/circle.png)\n\nThe `cientos` package provides a `<Circle />` component that serves as a short-cut for a `CircleGeometry` and a `MeshBasicMaterial` with a `Mesh` object.\n\n```\nargs: [radius: number, segments: number, thetaStart: number, thetaLength: number]\n```\n\nReference: [CircleGeometry](https://threejs.org/docs/?q=circle#api/en/geometries/CircleGeometry)\n\n## Usage\n\n```vue\n<Circle :args=\"[1, 32]\" color=\"lightsalmon\" />\n\n// Circle with a custom material transformations\n<Circle ref=\"circleRef\" :args=\"[1, 32]\" :position=\"[0, 0, 0]\">\n  <TresMeshToonMaterial color=\"lightsalmon\" />\n</Circle>\n```\n"
  },
  {
    "path": "docs/guide/shapes/cone.md",
    "content": "# Cone <Badge type=\"warning\" text=\"^1.6.0\" />\n\n![](/cientos/cone.png)\n\nThe `cientos` package provides a `<Cone />` component that serves as a short-cut for a `ConeGeometry` and a `MeshBasicMaterial` with a `Mesh` object.\n\n```\nargs: [\n  radius: number,\n  height: number,\n  radialSegments: number,\n  heightSegments: number,\n  openEnded: boolean,\n  thetaStart: number,\n  thetaLength: number\n]\n```\n\nReference: [ConeGeometry](https://threejs.org/docs/?q=cone#api/en/geometries/ConeGeometry)\n\n## Usage\n\n```vue\n<Cone :args=\"[1, 1, 8]\" color=\"orange\" />\n\n// Cone with a custom material transformations\n<Cone ref=\"coneRef\" :args=\"[1, 1, 8]\" :position=\"[0, 4, 0]\">\n  <TresMeshToonMaterial color=\"orange\" />\n</Cone>\n```\n"
  },
  {
    "path": "docs/guide/shapes/cubic-bezier-line.md",
    "content": "# CubicBezierLine\n\n<DocsDemo>\n  <CubicBezierLineDemo />\n</DocsDemo>\n\n`<CubicBezierLine />` renders a `<Line2 />` between start and end points, with additional 2 control points.\n\n## Usage\n<<< @/.vitepress/theme/components/CubicBezierLineDemo.vue\n\n## Props\n\n`<CubicBezierLine />` inherits all props but `points` from `<Line2 />`.\n\n| Prop         | Type      | Description                                                                   | Default        |\n| ------------ | --------- | ----------------------------------------------------------------------------- | -------------- |\n| `start` | `Vector3 \\| [number, number, number]` | Starting point |            |\n| `end` | `Vector3 \\| [number, number, number]` | Ending point |            |\n| `midA` | `Vector3 \\| [number, number, number]` | First control point |            |\n| `midB` | `Vector3 \\| [number, number, number]` | Second control point |            |\n| `segments`     | `number`  | Number of segments in the resulting curve (higher = smoother) | 20             |\n"
  },
  {
    "path": "docs/guide/shapes/cylinder.md",
    "content": "# Cylinder <Badge type=\"warning\" text=\"^4.0.0\" />\n\n![](/cientos/cylinder.png)\n\nThe `cientos` package provides a `<Cylinder />` component that serves as a short-cut for a `CylinderGeometry` and a `MeshBasicMaterial` with a `Mesh` object.\n\n```\nargs: [\n  radiusTop: number,\n  radiusBottom: number,\n  height: number,\n  radialSegments: number,\n  heightSegments: number,\n  openEnded: boolean,\n  thetaStart: number,\n  thetaLength: number\n]\n```\n\nReference: [CylinderGeometry](https://threejs.org/docs/?q=cylinder#api/en/geometries/CylinderGeometry)\n\n## Usage\n\n```vue\n<Cylinder :args=\"[1, 1, 1, 32, 1, false, 0, Math.PI * 2]\" color=\"orange\" />\n\n// Cylinder with a custom material transformations\n<Cylinder ref=\"cylinderRef\" :args=\"[1, 1, 1, 32, 1, false, 0, Math.PI * 2]\" :position=\"[0, 4, 0]\">\n  <TresMeshToonMaterial color=\"orange\" />\n</Cylinder>\n```\n"
  },
  {
    "path": "docs/guide/shapes/dodecahedron.md",
    "content": "# Dodecahedron <Badge type=\"warning\" text=\"^1.6.0\" />\n\n![](/cientos/dodecahedron.png)\n\nThe `cientos` package provides a `<Dodecahedron />` component that serves as a short-cut for a `DodecahedronGeometry` and a `MeshBasicMaterial` with a `Mesh` object.\n\n```\nargs: [radius: number, detail: number]\n```\n\nReference: [DodecahedronGeometry](https://threejs.org/docs/?q=dode#api/en/geometries/DodecahedronGeometry)\n\n## Usage\n\n```vue\n<Dodecahedron :args=\"[1, 0]\" color=\"deeppink\" />\n\n// Dodecahedron with a custom material transformations\n<Dodecahedron ref=\"dodecahedronRef\" :args=\"[1, 0]\" :position=\"[2, 4, 0]\">\n  <TresMeshToonMaterial color=\"deeppink\" />\n</Dodecahedron>\n```\n"
  },
  {
    "path": "docs/guide/shapes/icosahedron.md",
    "content": "# Icosahedron <Badge type=\"warning\" text=\"^1.6.0\" />\n\n![](/cientos/icosahedron.png)\n\nThe `cientos` package provides a `<Icosahedron />` component that serves as a short-cut for a `IcosahedronGeometry` and a `MeshBasicMaterial` with a `Mesh` object.\n\n```\nargs: [radius: number, detail: number]\n```\n\nReference: [IcosahedronGeometry](https://threejs.org/docs/?q=ico#api/en/geometries/IcosahedronGeometry)\n\n## Usage\n\n```vue\n<Icosahedron :args=\"[1, 0]\" color=\"red\" />\n\n// Icosahedron with a custom material transformations\n<Icosahedron ref=\"icosahedronRef\" :args=\"[1, 0]\" :position=\"[2, 4, 0]\">\n  <TresMeshToonMaterial color=\"red\" />\n</Icosahedron>\n```\n"
  },
  {
    "path": "docs/guide/shapes/line2.md",
    "content": "# Line2\n\n<DocsDemo>\n  <Line2Demo />\n</DocsDemo>\n\nThe `cientos` package provides a `<Line2 />` component for creating 3-D lines. It wraps [Three.js's `Line2`](https://github.com/mrdoob/three.js/blob/e2bcdfff6427c2f106cb819b18d88d1e13aa508a/examples/jsm/lines/Line2.js).\n\n## Usage\n<<< @/.vitepress/theme/components/Line2Demo.vue{3,8-12}\n\n## Props\n\n| Prop            | Type                     | Description                                                                | Default        |\n| --------------- | -------------------------|--------------------------------------------------------------------------- | -------------- |\n| points          | [See below](#points)     | Points representing the line                                               |                |\n| vertexColors    | `TresColor[]`            | Vertex colors, if using                                                    | null           |\n| color           | `TresColor`              | Color for the line – multiplies vertex colors                              | 'white'        |\n| lineWidth       | `number`                 | Width of the line – in world units with size attenuation, pixels otherwise | 1              |\n| worldUnits      | `boolean`                | Whether the line width is in world units or pixels                         | false          |\n| alphaToCoverage | `boolean`                | Enables alpha to coverage. Can only be used with MSAA-enabled contexts (meaning when the renderer was created with antialias parameter set to true).                                                               | false          |\n| dashed          | `boolean`                | Whether the line is dashed                                                 | false          |\n| dashSize        | `number`                 | Dash size                                                                  | 1              |\n| gapSize         | `number`                 | Gap size in dashed line                                                    | 1              |\n| dashScale       | `number`                 | Scale of the dashes/gaps                                                   | 1              |\n| dashOffset      | `number`                 | Dash offset                                                                | 0              |\n\n### Points\n\nThe points prop has the following type:\n\n`Array<Vector3 | Vector2 | [number, number, number] | [number, number] | number>`\n\nThe passed array is converted to `Array<number>` – i.e., a series of x, y, z vertex coordinates. This is done array entry by array entry, as follows:\n\n| Entry type                   | Interpretation                                                                   |\n| ---------------------------- | -------------------------------------------------------------------------------- |\n| `Vector3`                    | Insert the vector's x, y, z into the result array                                |\n| <nobr>`[number, number, number]`</nobr> | Insert the array values into the result array                         |\n| `Vector2`                    | Insert the vector's x, y, then 0 into the result array                           |\n| `[number, number]`           | Insert the array values, then 0 into the result array                            |\n| `number`                     | Insert the number into the result array                                          |\n\n:::warning\nIf you pass \"bare\" numbers in the points array, ensure that you pass \"triplets\" – groups of three numbers. Otherwise, you'll corrupt the coordinates that follow.\n\n::: code-group\n```vue [Wrong]\n//        ✅     ❌     ✅\n:points=\"[[1,1], 2, 2, [3,3]]\"\n// result: (1,1,0) (2,2,3) (3,0,❌)\n```\n\n```vue [Right]\n//        ✅     ✅        ✅\n:points=\"[[1,1], 2, 2, 0, [3,3]]\"\n// result: (1,1,0) (2,2,0) (3,3,0)\n```\nThe component, like Three.js, will not keep you from shooting yourself in the foot.\n:::\n"
  },
  {
    "path": "docs/guide/shapes/octahedron.md",
    "content": "# Octahedron <Badge type=\"warning\" text=\"^1.6.0\" />\n\n![](/cientos/octahedron.png)\n\nThe `cientos` package provides a `<Octahedron />` component that serves as a short-cut for a `OctahedronGeometry` and a `MeshBasicMaterial` with a `Mesh` object.\n\n```\nargs: [radius: number, detail: number]\n```\n\nReference: [OctahedronGeometry](https://threejs.org/docs/?q=octa#api/en/geometries/OctahedronGeometry)\n\n## Usage\n\n```vue\n<Octahedron :args=\"[1, 0]\" color=\"red\" />\n\n// Octahedron with a custom material transformations\n<Octahedron ref=\"icosahedronRef\" :args=\"[1, 0]\" :position=\"[2, 4, 0]\">\n  <TresMeshToonMaterial color=\"red\" />\n</Octahedron>\n```\n"
  },
  {
    "path": "docs/guide/shapes/plane.md",
    "content": "# Plane <Badge type=\"warning\" text=\"^1.5.0\" />\n\n![](/cientos/plane.png)\n\nThe `cientos` package provides a `<Plane />` component that serves as a short-cut for a `PlaneGeometry` and a `MeshBasicMaterial` with a `Mesh` object.\n\n```\nargs: [width: number, height: number, widthSegments: number, heightSegments: number]\n```\n\nReference: [PlaneGeometry](https://threejs.org/docs/?q=plane#api/en/geometries/PlaneGeometry)\n\n::: info\nA convenient default rotation is applied to the _x-axis_ of the plane (`-Math.PI / 2`), so that it is facing up (along the Y axis).\n:::\n\n## Usage\n\n```vue\n<Plane :args=\"[1, 1]\" color=\"teal\" />\n\n// Plane with a custom material transformations\n<Plane ref=\"planeRef\" :args=\"[8, 8]\" :position=\"[0, 4, 0]\">\n  <TresMeshToonMaterial color=\"teal\" />\n</Plane>\n```\n"
  },
  {
    "path": "docs/guide/shapes/quadratic-bezier-line.md",
    "content": "# QuadraticBezierLine\n\n<DocsDemo>\n  <QuadraticBezierLineDemo />\n</DocsDemo>\n\n`<QuadraticBezierLine />` renders a `<Line2 />` between start and end points, with an optional control point.\n\n## Usage\n<<< @/.vitepress/theme/components/QuadraticBezierLineDemo.vue\n\n## Props\n\n`<QuadraticBezierLine />` inherits all props but `points` from `<Line2 />`.\n\n| Prop         | Type      | Description                                                                   | Default        | Required |\n| ------------ | --------- | ----------------------------------------------------------------------------- | -------------- | ---- |\n| `start` | `Vector3 \\| [number, number, number]` | Starting point |        | yes |\n| `end` | `Vector3 \\| [number, number, number]` | Ending point |            | yes |\n| `mid` | `Vector3 \\| [number, number, number]` | Control point |           | no |\n| `segments`     | `number`  | Number of segments in the resulting curve (higher = smoother) | 20 | no |\n"
  },
  {
    "path": "docs/guide/shapes/ring.md",
    "content": "# Ring <Badge type=\"warning\" text=\"^1.6.0\" />\n\n![](/cientos/ring.png)\n\nThe `cientos` package provides a `<Ring />` component that serves as a short-cut for a `RingGeometry` and a `MeshBasicMaterial` with a `Mesh` object.\n\n```\nargs: [\n  innerRadius: number,\n  outerRadius: number,\n  thetaSegments: number,\n  phiSegments: number,\n  thetaStart: number,\n  thetaLength: number\n]\n```\n\nReference: [RingGeometry](https://threejs.org/docs/?q=ring#api/en/geometries/RingGeometry)\n\n## Usage\n\n```vue\n<Ring :args=\"[0.5, 1, 32]\" color=\"purple\" />\n\n// Ring with a custom material transformations\n<Ring ref=\"ringRef\" :args=\"[0.5, 1, 32]\" :position=\"[2, 4, 0]\">\n  <TresMeshToonMaterial color=\"purple\" />\n</Ring>\n```\n"
  },
  {
    "path": "docs/guide/shapes/rounded-box.md",
    "content": "# RoundedBox\n\n<DocsDemo>\n  <RoundedBoxDemo />\n</DocsDemo>\n\nThe `cientos` package provides a `<RoundedBox />` component that serves as a short-cut for a `RoundedBoxGeometry` and a `MeshBasicMaterial` with a `Mesh` object.\n\n```\nargs: [\n  width: number, // default 1\n  height: number, // default 1\n  depth: number, // default 1\n  segments: number, // default 2\n  radius: number, // default 0.1\n]\n```\n\nReference: [RoundedBoxGeometry](https://github.com/mrdoob/three.js/blob/master/examples/jsm/geometries/RoundedBoxGeometry.js)\n\n## Usage\n\n```vue\n<RoundedBox :args=\"[1, 1, 1, 2, 0.1]\" color=\"orange\" />\n\n// RoundedBox with a custom material transformations\n<RoundedBox ref=\"boxRef\" :position=\"[0, 4, 0]\">\n  <TresMeshToonMaterial color=\"orange\" />\n</RoundedBox>\n```\n"
  },
  {
    "path": "docs/guide/shapes/screen-quad.md",
    "content": "# ScreenQuad\n\nA triangle that fills the screen when using a THREE.OrthographicCamera. Useful for full-screen fragment shader work.\n\n## Usage\n\n<<< @/.vitepress/theme/components/ScreenQuadDemo.vue\n\n## References\n\n* [Why a triangle?](https://www.cginternals.com/en/blog/2018-01-10-screen-aligned-quads-and-triangles.html)\n* [Simple postprocessing in THREE.js](https://luruke.medium.com/simple-postprocessing-in-three-js-91936ecadfb7)\n"
  },
  {
    "path": "docs/guide/shapes/sphere.md",
    "content": "# Sphere <Badge type=\"warning\" text=\"^1.6.0\" />\n\n![](/cientos/sphere.png)\n\nThe `cientos` package provides a `<Sphere />` component that serves as a short-cut for a `SphereGeometry` and a `MeshBasicMaterial` with a `Mesh` object.\n\n```\nargs: [\n  radius: number,\n  widthSegments: number,\n  heightSegments: number,\n  phiStart: number,\n  phiLength: number,\n  thetaStart: number,\n  thetaLength: number\n]\n```\n\nReference: [SphereGeometry](https://threejs.org/docs/?q=sphere#api/en/geometries/SphereGeometry)\n\n## Usage\n\n```vue\n<Sphere :args=\"[1, 1, 1]\" color=\"pink\" />\n\n// Sphere with a custom material transformations\n<Sphere ref=\"planeRef\" :args=\"[1, 1, 1]\" :position=\"[2, 4, 0]\">\n  <TresMeshToonMaterial color=\"pink\" />\n</Sphere>\n```\n"
  },
  {
    "path": "docs/guide/shapes/superformula.md",
    "content": "# Superformula\n\n<DocsDemo>\n  <SuperformulaLechesDemo />\n</DocsDemo>\n\nThe `cientos` package provides a `<Superformula />` component that produces a configurable [3D plot of the superformula](https://en.wikipedia.org/wiki/Superformula).\n\n## Usage\n<DocsDemo>\n  <SuperformulaDemo />\n</DocsDemo>\n\n<<< @/.vitepress/theme/components/SuperformulaDemo.vue{3,8-13}\n\n## Props\n\nThe `<Superformula />` 3D plot is the product of 2 2D superformulas, referred to as \"A\" and \"B\" in the props. See this [Wikipedia article about the superformula](https://en.wikipedia.org/wiki/Superformula) for more information about the function's arguments.\n\n<table><thead><tr class=\"row-header\"><th class=\"col-name\">Name</th><th class=\"col-description\">Description</th><th class=\"col-default\">Default</th></tr></thead><tbody><tr class=\"row-width-segments\"><td class=\"col-name\"><strong><nobr>widthSegments</nobr></strong></td><td class=\"col-description\">Number of horizontal mesh segments<br>\n</td><td class=\"col-default\"><code>32</code></td></tr><tr class=\"row-height-segments\"><td class=\"col-name\"><strong><nobr>heightSegments</nobr></strong></td><td class=\"col-description\">Number of vertical mesh segments<br>\n</td><td class=\"col-default\"><code>32</code></td></tr><tr class=\"row-num-arms-a\"><td class=\"col-name\"><strong><nobr>numArmsA</nobr></strong></td><td class=\"col-description\">For A, number of radial arms/ripples</td><td class=\"col-default\"><code>4</code></td></tr><tr class=\"row-exp-a\"><td class=\"col-name\"><strong><nobr>expA</nobr></strong></td><td class=\"col-description\">A's 3 exponents<br>\n</td><td class=\"col-default\"><code>[40,&nbsp;1.3,&nbsp;0.9]</code></td></tr><tr class=\"row-num-arms-b\"><td class=\"col-name\"><strong><nobr>numArmsB</nobr></strong></td><td class=\"col-description\">For B, number of radial arms/ripples<br>\n</td><td class=\"col-default\"><code>4</code></td></tr><tr class=\"row-exp-b1\"><td class=\"col-name\"><strong><nobr>expB</nobr></strong></td><td class=\"col-description\">B's 3 exponents<br>\n</td><td class=\"col-default\"><code>[40,&nbsp;1.3,&nbsp;0.9]</code></td></tr><tr class=\"row-color\"><td class=\"col-name\"><strong><nobr>color</nobr></strong></td><td class=\"col-description\">If no material is provided, a color for the default material<br>\n</td><td class=\"col-default\"><code>'white'</code></td></tr></tbody></table>\n\n## Slot\n\n`<Superformula />` has a single slot for an optional material.\n"
  },
  {
    "path": "docs/guide/shapes/tetrahedron.md",
    "content": "# Tetrahedron <Badge type=\"warning\" text=\"^1.6.0\" />\n\n![](/cientos/tetrahedron.png)\n\nThe `cientos` package provides a `<Tetrahedron />` component that serves as a short-cut for a `TetrahedronGeometry` and a `MeshBasicMaterial` with a `Mesh` object.\n\n```\nargs: [radius: number, detail: number]\n```\n\nReference: [TetrahedronGeometry](https://threejs.org/docs/?q=tetr#api/en/geometries/TetrahedronGeometry)\n\n## Usage\n\n```vue\n<Tetrahedron :args=\"[1, 0]\" color=\"yellow\" />\n\n// Tetrahedron with a custom material transformations\n<Tetrahedron ref=\"tetrahedronRef\" :args=\"[1, 0]\" :position=\"[2, 4, 0]\">\n  <TresMeshToonMaterial color=\"yellow\" />\n</Tetrahedron>\n```\n"
  },
  {
    "path": "docs/guide/shapes/torus-knot.md",
    "content": "# TorusKnot <Badge type=\"warning\" text=\"^1.6.0\" />\n\n![](/cientos/torus-knot.png)\n\nThe `cientos` package provides a `<TorusKnot />` component that serves as a short-cut for a `TorusKnotGeometry` and a `MeshBasicMaterial` with a `Mesh` object.\n\n```\nargs: [\n  radius: number,\n  tube: number,\n  tubularSegments: number,\n  radialSegments: number,\n  p: number,\n  q: number\n]\n```\n\nReference: [TorusKnotGeometry](https://threejs.org/docs/?q=torus#api/en/geometries/TorusKnotGeometry)\n\n## Usage\n\n```vue\n<TorusKnot :args=\"[0.6, 0.2, 64, 8]\" color=\"lime\" />\n\n// TorusKnot with a custom material transformations\n<TorusKnot ref=\"torusKnotRef\" :args=\"[0.6, 0.2, 64, 8]\" :position=\"[-2, 6, 2]\">\n  <TresMeshToonMaterial color=\"lime\" />\n</TorusKnot>\n```\n"
  },
  {
    "path": "docs/guide/shapes/torus.md",
    "content": "# Torus <Badge type=\"warning\" text=\"^1.6.0\" />\n\n![](/cientos/torus.png)\n\nThe `cientos` package provides a `<Torus />` component that serves as a short-cut for a `TorusGeometry` and a `MeshBasicMaterial` with a `Mesh` object.\n\n```\nargs: [\n  radius: number,\n  tube: number,\n  radialSegments: number,\n  tubularSegments: number,\n  arc: number\n]\n```\n\nReference: [TorusGeometry](https://threejs.org/docs/?q=torus#api/en/geometries/TorusGeometry)\n\n## Usage\n\n```vue\n<Torus :args=\"[2, 0.4, 42, 100]\" color=\"cyan\" />\n\n// Torus with a custom material transformations\n<Torus ref=\"torusRef\" :args=\"[0.75, 0.4, 16, 80]\" :position=\"[-2, 6, 0]\">\n  <TresMeshToonMaterial color=\"cyan\" />\n</Torus>\n```\n"
  },
  {
    "path": "docs/guide/shapes/tube.md",
    "content": "# Tube <Badge type=\"warning\" text=\"^1.6.0\" />\n\n![](/cientos/tube.png)\n\nThe `cientos` package provides a `<Tube />` component that serves as a short-cut for a `TubeGeometry` and a `MeshBasicMaterial` with a `Mesh` object.\n\nReference: [TubeGeometry](https://threejs.org/docs/?q=tube#api/en/geometries/TubeGeometry)\n\n## Usage\n\n```\n<script>\nexport default {\n  setup() {\n    const tubePath = ref(new CubicBezierCurve3(\n          new Vector3(-1, 0, 0),\n          new Vector3(-0.5, -1, 0),\n          new Vector3(0.5, 1, 0),\n          new Vector3(1, 0, 0),\n          ));\n\n    return {\n      tubePath\n    }\n  },\n}\n</script>\n```\n\n```vue\n// TubeGeometry needs a curve path to be construct\n<Tube :args=\"[tubePath, 20, 0.2, 8, false]\" color=\"lightblue\" />\n\n// Tube with a custom material transformations\n<Tube ref=\"tubeRef\" :args=\"[tubePath, 20, 0.2, 8, false]\" :position=\"[0, 4, 0]\">\n  <TresMeshToonMaterial color=\"lightblue\" />\n</Tube>\n```\n\n## Args\n\n```\ntype CurveType = QuadraticBezierCurve3 | CubicBezierCurve3 | CatmullRomCurve3 | LineCurve3\n\nargs: [\n  path: CurveType,\n  tubularSegments: number,\n  radius: number,\n  radialSegments: number,\n  closed: boolean\n]\n```\n"
  },
  {
    "path": "docs/guide/staging/accumulative-shadows.md",
    "content": "# AccumulativeShadows\n\n<DocsDemo>\n  <AccumulativeShadowsDemo />\n</DocsDemo>\n\n`<AccumulativeShadows />` is a `THREE.DirectionalLight`-based shadow component. It displays shadows on a single shadow catcher plane, included in the component. It is based on [Drei component of the same name](http://drei.docs.pmnd.rs/staging/accumulative-shadows).\n\n## Usage\n\n<<< @/.vitepress/theme/components/AccumulativeShadowsDemo.vue\n\n## Props\n\n| Prop | Description | Default |\n| - | - | - |\n| `once` | Whether shadow creation only happens once (resets after props change) | `false` |\n| `accumulate` | Whether shadows accumulate progressively over several frames | `true` |\n| `frames` | Number of frames to render. More yields cleaner results but takes more time. If `accumulate && once`, 1 frame will be consumed every update for `frames` updates. Otherwise, `frames` frames are consumed for every update. | `40` |\n| `blend` | If `accumulate`, controls the refresh ratio | `100` |\n| `limit` | If less than `Infinity`, limits the amount of frames rendered. Use this to increase performance once a movable scene has settled | `Infinity` |\n| `scale` | Scale of the plane | `10` |\n| `opacity` | Opacity of the plane | `1` |\n| `alphaTest` | Discards alpha pixels | `0.65` |\n| `color` | Shadow color | `'black'` |\n| `colorBlend` | If less than `Infinity`, limits the amount of frames rendered. Use this to increase performance once a movable scene has settled | `Infinity` |\n| `resolution` | Buffer resolution | `1024` |\n| `toneMapped` | Texture tonemapping | `true` |\n\n## Slot\n\nYou can bring your own lights to `<AccumulatedShadows />`, but it's designed to be used with `<RandomizedLights />`.\n\nBy default, there's a `<RandomizedLights />` instance provided in `<AccumulatedShadows />`'s `<slot />`. You can replace it with your own `<RandomizedLights />` or an alternative by passing it as a child component.\n"
  },
  {
    "path": "docs/guide/staging/align.md",
    "content": "# Align\n\n<DocsDemo>\n  <AlignDemo />\n</DocsDemo>\n\nCalculates a bounding box around its children and aligns them as a group within their parent. The component measures its contents and realigns on every frame unless `cacheKey` is set.\n\n## Usage\n\n<<< @/.vitepress/theme/components/AlignDemo.vue\n\n## Props\n\nAll props are optional.\n\n| Prop         | Description                         |\n| ------------ | ----------------------------------- |\n| `top`        | If `true`, aligns bounding box bottom to `0` on the y-axis |\n| `bottom`     | If `true`, aligns bounding box top to `0` on the y-axis. |\n| `left`       | If `true`, aligns bounding box right to `0` on the x-axis. |\n| `right`      | If `true`, aligns bounding box left to `0` on the x-axis. |\n| `front`      | If `true`, aligns bounding box back to `0` on the z-axis. |\n| `back`       | If `true`, aligns bounding box front to `0` on the z-axis. |\n| `disable`    | If `true`, disables alignment on all axes. |\n| `disableX`   | If `true`, disables alignment on the x-axis. |\n| `disableY`   | If `true`, disables alignment on the y-axis. |\n| `disableZ`   | If `true`, disables alignment on the z-axis. |\n| `precise`    | See [Box3.setFromObject](https://threejs.org/docs/index.html?q=box3#api/en/math/Box3.setFromObject). |\n| `onAlign`    | Callback that fires when updating, after measurement. |\n| `cacheKey`   | If set, component will only update when `cacheKey`'s value changes. If unset, component will update every frame. |\n\n## `AlignCallbackOptions`\n\n```ts\nexport interface AlignCallbackOptions {\n  /** The next parent above <Align /> */\n  parent: Object3D\n  /** The outmost container group of the <Align/> component */\n  container: Object3D\n  width: number\n  height: number\n  depth: number\n  boundingBox: Box3\n  boundingSphere: Sphere\n  center: Vector3\n  verticalAlignment: number\n  horizontalAlignment: number\n  depthAlignment: number\n}\n```\n"
  },
  {
    "path": "docs/guide/staging/backdrop.md",
    "content": "# Backdrop\n\n<DocsDemo>\n    <BackdropDemo class=\"demo-scene\" />\n</DocsDemo>\n\nThe `cientos` package provides a `<Backdrop />` component. It's just a curved plane, like a studio backdrop. Meant is for presentational purposes, to break up light and shadows more interestingly.\n\n## Usage\n\n```vue\n<Backdrop />\n\n// Backdrop with a custom material\n<Backdrop\n  :floor=\"1.5\"\n  :segments=\"20\"\n  receive-shadow\n>\n    <TresMeshPhysicalMaterial color=\"orange\" :roughness=\"1\" />\n</Backdrop>\n```\n\n## Props\n\n| Name | Type | Default | Required |\n| :--- | :--- | ------- | -------- |\n| floor | number | `0.25` | No |\n| segments | number | `20` | No |\n| receiveShadow | boolean | `false` | No |\n"
  },
  {
    "path": "docs/guide/staging/bounds.md",
    "content": "# Bounds\n\n<DocsDemo>\n    <BoundsDemo />\n</DocsDemo>\n\nCalculates a boundary box and centers the camera accordingly. Its `lookAt` method accepts a target to look at imperatively e.g., after a click.\n\n::: info\nIf you are using other camera controls, be sure to make them the 'default'.\n```vue\n<OrbitControls make-default />\n```\n:::\n\n## Usage\n\n<<< @/.vitepress/theme/components/BoundsDemo.vue\n\n## Props\n\n| Name | Description | Default |\n| :--- | :--- | ---- |\n| `duration` | Duration of the `lookAt` animation in seconds | `1.0` |\n| `offset` | Additional distance from the target when using `lookAt` with a `Box3` or `Object3D` | `0.2` |\n| `useResize` | Whether to re`lookAt` the last target when the screen is resized | `false` |\n| `useMounted` | Whether to `lookAt` the `Bounds` object when the component is mounts | `false` |\n| `clip` | Whether to adjust the camera's `near` and `far` settings when using `lookAt` | `false` |\n| `easing` | Animation's easing function. `t` and the returned value should be in the interval `[0, 1]` | Cubic ease out |\n\n## `lookAt`\n\n`<Bounds />` `lookAt` points the camera at its first argument: an `Object3D`, `Box3` or `Vector3`.\n\n```\n  /**\n   * Calculates a boundary box around an `Object3D` and centers the camera accordingly.\n   */\n  lookAt(object: Object3D): void\n  /**\n   * Calculates a boundary box around an `Object3D` and centers the camera accordingly and animates the camera's `up` vector.\n   */\n  lookAt(object: Object3D, up: VectorFlexibleParams): void\n  /**\n   * Centers the camera's viewport on a `Box3`.\n   */\n  lookAt(box3: Box3): void\n  /**\n   * Centers the camera's viewport on a `Box3` and animates the camera's `up` vector.\n   */\n  lookAt(box3: Box3, up: VectorFlexibleParams): void\n  /**\n   * Look at a `Vector3`.\n   */\n  lookAt(target: VectorFlexibleParams): void\n  /**\n   * Look at a `Vector3`, if provided. Move the camera to `position`.\n   */\n  lookAt(target: VectorFlexibleParams | undefined | null, position: VectorFlexibleParams): void\n  /**\n   * Look at a `Vector3`, if provided. Move the camera to `position` and animate the camera's `up` vector.\n   */\n  lookAt(target: VectorFlexibleParams | undefined | null, position: VectorFlexibleParams, up: VectorFlexibleParams): void\n  /**\n   * Rerun `lookAt` using the prior arguments. If `lookAt` has never been called, uses the `Bounds` object.\n   */\n  lookAt(): void\n```\n"
  },
  {
    "path": "docs/guide/staging/circle-shadow.md",
    "content": "# CircleShadow\n\n<DocsDemo>\n    <CircleShadowDemo />\n</DocsDemo>\n\n`<CircleShadow />` is a cheap, texture-based radial gradient on a `THREE.PlaneGeometry`.\n\n## Usage\n\n<<< @/.vitepress/theme/components/CircleShadowDemo.vue\n\n## Props\n\nAll props are optional.\n\n| Name | Description | Default |\n| :--- | :--- | ------- |\n| `color` | Color of the shadow as a `Color \\| number \\| string` | `'black'` |\n| `opacity` | Opacity of the shadow | `0.5` |\n| `offset` | Placement of the first radial gradient color stop. `0.0` is the center of the circle. `1.0` is edge. | `0` |\n| `fog` | Whether the material is affected by fog | `false` |\n| `depthWrite` | Whether rendering the material has any effect on the depth buffer | `false` |\n"
  },
  {
    "path": "docs/guide/staging/contact-shadows.md",
    "content": "# ContactShadows\n\n<DocsDemo>\n  <ContactShadowsDemo />\n</DocsDemo>\n\n`<ContactShadows />` is a \"fake\", non-lighting-based shadow component. It displays shadows on a single plane. The component is based on the [THREE.js contact shadows example](https://threejs.org/examples/webgl_shadow_contact.html) by [@mrdoob](https://twitter.com/mrdoob).\n\n## Usage\n\n<<< @/.vitepress/theme/components/ContactShadowsDemo.vue\n\n## Props\n\n| Prop         | Description                                                                    | Default     |\n| ------------ | ------------------------------------------------------------------------------ | ----------- |\n| `opacity`    | The opacity of the shadows.                                                    | `1`         |\n| `blur`       | The blur of the shadows.                                                       | `1`         |\n| `color`      | The color of the shadows.                                                      | `'#000000'` |\n| `tint`       | If provided, the color of the \"core\" of the shadows. \"Added\" to `color`.       | `undefined` |\n| `scale`      | The scale of the shadows/shadow plane. Can be a number or an array of two numbers `[x, y]`. | 10        |\n| `width`      | The width of the shadow plane.                                                 | `1`         |\n| `height`     | The height of the shadow plane.                                                | `1`         |\n| `far`        | The distance of the orthographic shadow camera extends above the shadow plane. | `10`        |\n| `smooth`     | Whether the shadows should be smoothed to reduce artifacts.                    | `true`      |\n| `resolution` | The resolution of the shadow textures.                                         | `512`       |\n| `frames`     | For performance, optionally stop updating shadows after `frames` frames.       | `Math.POSITIVE_INFINITY`  |\n| `depthWrite` | Whether the shadows should write to the depth buffer or not.                   | `false`     |\n"
  },
  {
    "path": "docs/guide/staging/environment.md",
    "content": "# Environment\r\n\r\n<DocsDemo>\r\n  <EnvironmentDemo />\r\n</DocsDemo>\r\n\r\nIs a component abstraction that automatically sets up a global cubemap, which affects the default `scene.environment`, and optionally `scene.background`.\r\n\r\nIt uses the composable [useEnvironment](/guide/staging/use-environment) under the hood to load the cubemap.\r\n\r\n## Usage\r\n\r\n```vue\r\n<Suspense>\r\n  <Environment\r\n    :files=\"[\r\n      '/px.jpg',\r\n      '/nx.jpg',\r\n      '/py.jpg',\r\n      '/ny.jpg',\r\n      '/pz.jpg',\r\n      '/nz.jpg'\r\n    ]\"\r\n  />\r\n</Suspense>\r\n```\r\n\r\nYou can also pass the `.hdr` file directly:\r\n\r\n```vue\r\n<Suspense>\r\n   <Environment files=\"/sunset.hdr\" />\r\n</Suspense>\r\n```\r\n\r\n![Environment](/cientos/envmaps.png)\r\n\r\n## Texture reference\r\n\r\nYou can access the model reference by passing a `ref` to the `<Environment />` prop and then using the method `getTexture()` to get the object.\r\n\r\n```vue{4,6,9,14,17}\r\n<script setup lang=\"ts\">\r\nimport { Environment } from '@tresjs/cientos'\r\n\r\nconst environmentRef = shallowRef()\r\n\r\nwatch(environmentRef, texture => {\r\n  console.log(texture)\r\n})\r\n</script>\r\n\r\n<template>\r\n  <Environment ref=\"environmentRef\" />\r\n  <TresMesh>\r\n    <TresSphereGeometry />\r\n    <TresMeshStandardMaterial :env-map=\"envMap\" />\r\n  </TresMesh>\r\n</template>\r\n```\r\n\r\n## Presets\r\n\r\nYou can use one of the available presets by passing the `preset` prop:\r\n\r\n```vue\r\n<Environment preset=\"city\" />\r\n```\r\n\r\n## Lightformer\r\n\r\nYou can incorporate `Lightformer` into the environment just like a slot.\r\n\r\n```vue\r\n<script setup>\r\nimport { Enviroment, LightFormer } from '@tres/cientos'\r\n</script>\r\n\r\n<template>\r\n  <Environment>\r\n    <Lightformer :intensity=\"0.75\" :position=\"[0, 5, -9]\" />\r\n    <Lightformer from=\"ring\" :rotation-y=\"-Math.PI / 2\" :scale=\"[10, 10, 1]\" />\r\n  </Environment>\r\n</template>\r\n```\r\n\r\n## Environment Rotation\r\n\r\nThe environment component supports both background and environment rotation. You can control them independently or sync them together:\r\n\r\n```vue\r\n<template>\r\n  <Environment\r\n    preset=\"sunset\"\r\n    :background=\"true\"\r\n    :background-rotation=\"[0, Math.PI / 2, 0]\"\r\n    :environment-rotation=\"[0, Math.PI / 4, 0]\"\r\n  />\r\n</template>\r\n```\r\n\r\n### Syncing Rotations\r\n\r\nYou can sync the environment rotation with the background rotation using the `syncMaterials` prop:\r\n\r\n```vue\r\n<template>\r\n  <Environment\r\n    preset=\"sunset\"\r\n    :background=\"true\"\r\n    :sync-materials=\"true\"\r\n    :background-rotation=\"[0, Math.PI / 2, 0]\"\r\n  />\r\n</template>\r\n```\r\n\r\nWhen `syncMaterials` is enabled:\r\n- The environment rotation will automatically match the background rotation\r\n- All materials in the scene will update to reflect the new rotation\r\n- This ensures visual consistency between the background and environment reflections\r\n\r\n## Props\r\n\r\n| Prop | Description | Default |\r\n| :----------- | :-------------------------------------------------------------------------- | -------------------------------------------------------------------------------- |\r\n| `files` | Array of 6 urls to images, one for each side of the CubeTexture, or an HDR file | `undefined` |\r\n| `path` | Path to the environment map files | `undefined` |\r\n| `encoding` | Encoding of the environment map | `SRGBColorSpace` for array files, `LinearEncoding` for single texture |\r\n| `background` | If `true`, the environment map will be used as the scene background | `false` |\r\n| `blur` | Blur factor between 0 and 1 (only works with three 0.146 and up) | 0 |\r\n| `preset` | Preset environment map | `undefined` |\r\n| `resolution` | The resolution of the WebGLCubeRenderTarget | 256 |\r\n| `near` | The near of the CubeCamera | 1 |\r\n| `far` | The far of the CubeCamera | 1000 |\r\n| `frames` | The frames of the cubeCamera.update | Infinity |\r\n| `backgroundIntensity` | Intensity of the background | 1 |\r\n| `environmentIntensity` | Intensity of the environment | 1 |\r\n| `backgroundRotation` | Rotation of the background (in radians) | [0, 0, 0] |\r\n| `environmentRotation` | Rotation of the environment (in radians) | [0, 0, 0] |\r\n| `syncMaterials` | If true, environment rotation will sync with background rotation | false |\r\n\r\n### Props for Lightformer\r\n\r\nLightformer inherits from mesh, and its extension parameters include:\r\n| Prop | Description | Default |\r\n| :----------- | :------------------------------------------------------------------- | -------------------------------------------------------------------------------- |\r\n| `from` | 'circle', 'ring', 'rect', or any other Mesh type | `rect` |\r\n| `intensity` | The intensity of the light | 1 |\r\n| `color` | The color of the light | `0xffffff` |\r\n| `args` | The arguments of the Geometry | When using other geometries, set the corresponding arguments |\r\n"
  },
  {
    "path": "docs/guide/staging/fit.md",
    "content": "# Fit\n\n<DocsDemo>\n  <FitDemo />\n</DocsDemo>\n\n`<Fit />` uniformly scales and positions its children as a group. By default, it fits its children into a 1 × 1 × 1 box at the world origin.\n\nAlternatively, the children can be fit into a `Box3` or an `Object3D`.\n\nOr the children can simply be resized. With `<Fit />` the children are scaled relative to the center of their calculated bounding box.\n\n## Usage\n\n<<< @/.vitepress/theme/components/FitDemo.vue{3,20-27}\n\n## Props\n\n<table><thead><tr class=\"row-header\"><th class=\"col-name\">Name</th><th class=\"col-description\">Description</th></tr></thead><tbody><tr class=\"row-into\"><td class=\"col-name\"><strong>into</strong></td><td class=\"col-description\">If <code>into</code> is:\n<ul>\n<li>omitted or explicitly <code>undefined</code>: position/scale children to fit into a 1 × 1 × 1 <code>Box3</code> at world origin.</li>\n<li><code>null</code>: turn off <code>&lt;Fit /&gt;</code>; reset scale/position of children.</li>\n<li><code>number</code>: convert argument to <code>Vector3(number, number, number)</code>.</li>\n<li><code>[number, number, number]</code>: convert argument to <code>Vector3</code>.</li>\n<li><code>Vector3</code>: position/scale children to fit inside a <code>Box3</code> of size <code>Vector3</code> at target objects' cumulative center.</li>\n<li><code>Box3</code>: position/scale children to fit inside <code>Box3</code>.</li>\n<li><code>Object3D</code>: position/scale children to fit inside calculated <code>Box3</code>. <a href=\"https://threejs.org/docs/#api/en/math/Box3.setFromObject\">See <code>THREE.Box3.setFromObject</code></a>. <code>&lt;Fit /&gt;</code> must not contain the <code>Object3D</code> and vice-versa.</li>\n</ul>\n<p>default:<br><code>new Box3(new Vector3(-0.5, -0.5, -0.5), new Vector3(0.5, 0.5, 0.5))</code></p></td></tr><tr class=\"row-precise\"><td class=\"col-name\"><strong>precise</strong></td><td class=\"col-description\"><a href=\"https://threejs.org/docs/index.html?q=box3#api/en/math/Box3.setFromObject\">See <code>precise</code> argument in <code>THREE.Box3.setFromObject</code></a><br>\n<p>default:<br><code>false</code></p></td></tr></tbody></table>\n"
  },
  {
    "path": "docs/guide/staging/grid.md",
    "content": "# Grid\n\n<DocsDemo>\n  <GridDemo />\n</DocsDemo>\n\n`<Grid />` creates a shader-based grid plane. It has customizable grid cell and section lines, as well as fade out.\n\n## Usage\n\n<<< @/.vitepress/theme/components/GridDemo.vue\n\n## Props\n\n| Prop                   | Description            | Default |\n| :--------------------- | :--------------------- | ------- |\n| **cellSize**           | Cell size | `0.5`      |\n| **cellThickness**      | Thickness of cell lines | `0.5`   |\n| **cellColor**          | Color of cell lines    | `'black'` |\n| **sectionSize**        | Section size           | `1`      |\n| **sectionThickness**   | Thickness of section lines | `1`   |\n| **sectionColor**       | Color of cell lines    | `'blue'` |\n| **followCamera**       | Whether to follow camera | `false`     |\n| **infiniteGrid**       | Whether to display an infinite grid | `false` |\n| **fadeDistance**       | Fade distance          | `100`    |\n| **fadeStrength**       | Fade strength          | `1`    |\n| **fadeFrom**           | Fade from camera (1) or origin (0) or in between | `1` |\n| **side**               | Material side          | `THREE.BackSide` |\n"
  },
  {
    "path": "docs/guide/staging/ocean.md",
    "content": "# Ocean\n\n<DocsDemo>\n  <OceanDemo />\n</DocsDemo>\n\n`<Ocean />` is a wrapper for the [Three.js `Water` add-on](https://threejs.org/examples/?q=ocean#webgl_shaders_ocean).\n\n::: warning\n`<Ocean />` comes with a default texture, so it needs to be wrapped in a Suspense component.\n:::\n\n## Usage\n\n### SKY\n\n`<Ocean />` works hand in hand with the Sky component, detecting the position of the sun and reflecting on the water.\n(`<Sky />` is not required for making this component work.)\n\n### Fog\n\nThe `<Ocean />` component also reacts when there's [Fog](https://threejs.org/docs/index.html?q=fog#api/en/scenes/Fog) or [FogExp2](https://threejs.org/docs/index.html?q=fog#api/en/scenes/FogExp2) in your scene.\n\n## Custom Geometry\n\nYou can use custom geometry by adding it as a child.\n\n```HTML\n<Suspense>\n  <Ocean>\n    <TresCircleGeometry :args=\"[50, 16]\" />\n  </Ocean>\n</Suspense>\n```\n\n## Props\n\n::: warning\nAll of the props of this component are not reactive.\n:::\n\n| Prop                | Description                                  | Default                                                                                          |\n| :------------------ | :------------------------------------------- | ------------------------------------------------------------------------------------------------ |\n| **textureWidth**    | Width of the mirror texture                  | 512                                                                                              |\n| **textureHeight**   | Height of the mirror texture                 | 512                                                                                              |\n| **waterNormals**    | Normals of the water                         | https://raw.githubusercontent.com/Tresjs/assets/main/textures/water-normals/Water_1_M_Normal.jpg |\n| **sunDirection**    | Sun direction to be reflected on the water   | Vector3(0,0,0)                                                                                   |\n| **sunColor**        | Sun color to be reflected on the water       | 0xffffff                                                                                         |\n| **waterColor**      | Water Color                                  | 0x001e0f                                                                                         |\n| **distortionScale** | Distortion scale on reflected objects        | 3.7                                                                                              |\n| **size**            | Size of the water normals                    | 1                                                                                                |\n| **clipBias**        | To use the clipBias property                 | 0.0                                                                                              |\n| **alpha**           | To use the clipBias Alpha                    | 1.0                                                                                              |\n| **side**            | Which size of the mesh will render the water | FrontSide                                                                                        |\n"
  },
  {
    "path": "docs/guide/staging/precipitation.md",
    "content": "# Precipitation\n\n`<Precipitation />` is a fully flexible component that renders an infinite particle flow, It comes with several props that allow you customize it to create different effects like precipitation, snow, waterfall, beams, etc.\n\n<DocsDemo>\n  <PrecipitationDemo />\n</DocsDemo>\n\n## Usage\n\nYou can use `<Precipitation />` component without passing any props, this will achieve a snowy effect, like the before example.\n\n<<< @/.vitepress/theme/components/PrecipitationDemo.vue{3,9}\n\n### Rain\n\nBy setting the randomness to 0, increase the speed  and reduce the count. You can easily achieve a more rainy effect.\n\n<DocsDemo>\n  <PrecipitationRainDemo />\n</DocsDemo>\n\n<<< @/.vitepress/theme/components/PrecipitationRainDemo.vue{3,9-13}\n\n### Storm\n\nA storm effect? Easy just increase the randomness.\n\n<DocsDemo>\n  <PrecipitationStormDemo />\n</DocsDemo>\n\n<<< @/.vitepress/theme/components/PrecipitationStormDemo.vue{3,9-13}\n\n### Beam\n\nWhat about an infinite beam? Just set the area, to the axis that you need constrain.\n\n<DocsDemo>\n  <PrecipitationBeamDemo />\n</DocsDemo>\n\n<<< @/.vitepress/theme/components/PrecipitationBeamDemo.vue{3,9-15}\n\nYou can create much more! ☔\n\n::: warning\nBe careful with the performance this components render infinite particles in movement\n:::\n\n## Props\n\n| Prop                | Description                                             | Default      |\n| :------------------ | :------------------------------------------------------ | ------------ |\n| **size**            | The size of the drops.                                  | 0.1          |\n| **area**            | The size of the precipitation area.                              | [10, 10, 20] |\n| **color**           | The color of the drops.                                  | 0xffffff     |\n| **map**             | Color texture of the drops.                             | null         |\n| **alphaMap**        | Alpha texture of the Drops.                             | null         |\n| **alphaTest**       | Enables the WebGL to know when not to render the pixel. | 0.01         |\n| **opacity**         | Set the opacity of the drops.                           | 0.8          |\n| **count**           | Number of drops.                                        | 5000         |\n| **speed**           | Drops speed.                                            | 0.1          |\n| **randomness**      | Add randomness to the drops.                            | 0.5          |\n| **depthWrite**      | Whether should write to the depth buffer or not. drops. | true         |\n| **transparent**     | Transparency on the drops texture                       | false        |\n| **sizeAttenuation** | Keep the same size regardless distance. drops.          | true         |\n"
  },
  {
    "path": "docs/guide/staging/randomized-lights.md",
    "content": "# RandomizedLights\n\n`<RandomizedLights />` internally creates multiple lights and jiggles them. You would normally add it as a child of `<AccumulativeShadows />`.\n\nIt is based on this [Drei component](http://drei.docs.pmnd.rs/staging/randomized-light).\n\n## Usage\n\n```vue\n  <RandomizedLights\n    :ambient=\"0.25\"\n    :bias=\"0.001\"\n    :count=\"8\"\n    :intensity=\"Math.PI\"\n    :map-size=\"1024\"\n    :position=\"[5, 5, -10]\"\n    :radius=\"2\"\n  />\n```\n\n## Props\n\n| Prop | Description | Default |\n| - | - | - |\n| `count` | Number of lights | `8`|\n| `radius` | Radius of the jiggle, higher values make softer light | `1` |\n| `intensity` | Light intensity | `Math.PI` |\n| `ambient` | \"Ambient occlusion\" to directional light ratio, lower values mean less AO | `0.5` |\n| `castShadow` | If the lights cast shadows | `true` |\n| `bias` | Default shadow bias | `0` |\n| `mapSize` | Size of the lights' shadow map | `512` |\n| `size` | Size of the lights' shadow camera frustum | `10` |\n| `near` | Lights' shadow camera near value | `0.5` |\n| `far` | Lights' shadow camera far value | `500` |\n| `position` | Position | `[5, 5, -10]` |\n"
  },
  {
    "path": "docs/guide/staging/sky.md",
    "content": "# Sky\n\n<DocsDemo>\n<SkyDemo />\n</DocsDemo>\n\n`<Sky />` is a wrapper for the [Three.js `Sky` add-on](https://threejs.org/examples/?q=sky#webgl_shaders_sky).\n\n## Usage\n\n<<< @/.vitepress/theme/components/SkyDemo.vue{3,9}\n\n## Props\n\n<table><thead><tr class=\"row-header\"><th class=\"col-name\">Name</th><th class=\"col-type\">Type</th><th class=\"col-description\">Description</th><th class=\"col-default\">Default</th><th class=\"col-required\">Required</th></tr></thead><tbody><tr class=\"row-turbidity\"><td class=\"col-name\"><strong>turbidity</strong></td><td class=\"col-type\"><code>number</code></td><td class=\"col-description\">Haziness<br>\n</td><td class=\"col-default\"><code>3.4</code></td><td class=\"col-required\">No</td></tr><tr class=\"row-rayleigh\"><td class=\"col-name\"><strong>rayleigh</strong></td><td class=\"col-type\"><code>number</code></td><td class=\"col-description\"><a href=\"https://en.wikipedia.org/wiki/Rayleigh_scattering\">Rayleigh scattering</a><br>\n</td><td class=\"col-default\"><code>3</code></td><td class=\"col-required\">No</td></tr><tr class=\"row-mie-coefficient\"><td class=\"col-name\"><strong>mieCoefficient</strong></td><td class=\"col-type\"><code>number</code></td><td class=\"col-description\"><a href=\"https://en.wikipedia.org/wiki/Mie_scattering\">Mie scattering</a> amount<br>\n</td><td class=\"col-default\"><code>0.005</code></td><td class=\"col-required\">No</td></tr><tr class=\"row-mie-directional-g\"><td class=\"col-name\"><strong>mieDirectionalG</strong></td><td class=\"col-type\"><code>number</code></td><td class=\"col-description\"><a href=\"https://en.wikipedia.org/wiki/Mie_scattering\">Mie scattering</a> direction<br>\n</td><td class=\"col-default\"><code>0.7</code></td><td class=\"col-required\">No</td></tr><tr class=\"row-elevation\"><td class=\"col-name\"><strong>elevation</strong></td><td class=\"col-type\"><code>number</code></td><td class=\"col-description\">Sun's elevation from the horizon, in degrees<br>\n</td><td class=\"col-default\"><code>0.6</code></td><td class=\"col-required\">No</td></tr><tr class=\"row-azimuth\"><td class=\"col-name\"><strong>azimuth</strong></td><td class=\"col-type\"><code>number</code></td><td class=\"col-description\">Sun's <a href=\"https://en.wikipedia.org/wiki/Solar_azimuth_angle\">azimuth angle</a>, in degrees – its horizontal coordinate on the horizon<br>\n</td><td class=\"col-default\"><code>180</code></td><td class=\"col-required\">No</td></tr><tr class=\"row-distance\"><td class=\"col-name\"><strong>distance</strong></td><td class=\"col-type\"><code>number</code></td><td class=\"col-description\">Sky box scale<br>\n</td><td class=\"col-default\"><code>450000</code></td><td class=\"col-required\">No</td></tr></tbody></table>\n"
  },
  {
    "path": "docs/guide/staging/smoke.md",
    "content": "# Smoke\n\n`<Smoke />` is a component that renders a smoke in your scene. It is an abstraction that use a combination of textures, transparency and some calculation, to create a beautiful  smoke - cloud - fog effect\n\n<DocsDemo>\n  <SmokeDemo />\n</DocsDemo>\n\n## Usage\n\n::: warning\nSmoke componente comes with a default texture abstraction it needs to be wrapped by a Suspense component\n:::\n\nYou can use `<Smoke />` component without passing any props, but still if you want you can tweak the props to find the best setup for you\n\n```vue\n<template>\n  <TresCanvas>\n    ...\n    <Suspense>\n      <Smoke />\n    </Suspense>\n    ...\n  </TresCanvas>\n</template>\n```\n\nNotice that you can pass a texture in combination with props,  to personalize your effect\n\n```vue\n<template>\n  <TresCanvas>\n    ...\n    <Suspense>\n      <Smoke\n        :speed=\"0.8\"\n        :segments=\"12\"\n        texture=\"my_texture_path\"\n        :color=\"#f7f\"\n      />\n    </Suspense>\n    ...\n  </TresCanvas>\n</template>\n```\n## Props\n\n<table><thead><tr class=\"row-header\"><th class=\"col-name\">Name</th><th class=\"col-type\">Type</th><th class=\"col-description\">Description</th><th class=\"col-default\">Default</th><th class=\"col-required\">Required</th></tr></thead><tbody><tr class=\"row-color\"><td class=\"col-name\"><strong><nobr>color</nobr></strong></td><td class=\"col-type\"><code>TresColor</code></td><td class=\"col-description\">The color of the smoke.<br>\n</td><td class=\"col-default\"><code>'#ffffff'</code></td><td class=\"col-required\">No</td></tr><tr class=\"row-opacity\"><td class=\"col-name\"><strong><nobr>opacity</nobr></strong></td><td class=\"col-type\"><code>number</code></td><td class=\"col-description\">The strength of the opacity.<br>\n</td><td class=\"col-default\"><code>0.5</code></td><td class=\"col-required\">No</td></tr><tr class=\"row-speed\"><td class=\"col-name\"><strong><nobr>speed</nobr></strong></td><td class=\"col-type\"><code>number</code></td><td class=\"col-description\">The rotation speed of the smoke.<br>\n</td><td class=\"col-default\"><code>0.4</code></td><td class=\"col-required\">No</td></tr><tr class=\"row-width\"><td class=\"col-name\"><strong><nobr>width</nobr></strong></td><td class=\"col-type\"><code>number</code></td><td class=\"col-description\">The base width.<br>\n</td><td class=\"col-default\"><code>10</code></td><td class=\"col-required\">No</td></tr><tr class=\"row-depth\"><td class=\"col-name\"><strong><nobr>depth</nobr></strong></td><td class=\"col-type\"><code>number</code></td><td class=\"col-description\">The base depth.<br>\n</td><td class=\"col-default\"><code>1.5</code></td><td class=\"col-required\">No</td></tr><tr class=\"row-segments\"><td class=\"col-name\"><strong><nobr>segments</nobr></strong></td><td class=\"col-type\"><code>number</code></td><td class=\"col-description\">The number of smoke to render.<br>\n</td><td class=\"col-default\"><code>20</code></td><td class=\"col-required\">No</td></tr><tr class=\"row-texture\"><td class=\"col-name\"><strong><nobr>texture</nobr></strong></td><td class=\"col-type\"><code>string</code></td><td class=\"col-description\">The texture of the smoke.<br>\n</td><td class=\"col-default\">default component texture</td><td class=\"col-required\">No</td></tr><tr class=\"row-depth-test\"><td class=\"col-name\"><strong><nobr>depthTest</nobr></strong></td><td class=\"col-type\"><code>boolean</code></td><td class=\"col-description\">The depthTest.<br>\n</td><td class=\"col-default\"><code>true</code></td><td class=\"col-required\">No</td></tr></tbody></table>\n"
  },
  {
    "path": "docs/guide/staging/soft-shadows.md",
    "content": "# SoftShadows\n\n<DocsDemo>\n    <SoftShadowsDemo />\n</DocsDemo>\n\nInjects percent closer soft shadows (pcss) into THREE's shader chunk. Mounting/unmounting this component or changing its props will cause all shaders to be recompiled.\n\n## Usage\n\n<<< @/.vitepress/theme/components/SoftShadowsDemo.vue\n\n## Props\n\n| Name | Description | Default |\n| :--- | :--- | ------- |\n| size | Size of the light source (the larger the softer the light) | `25` |\n| samples | Number of samples (more samples less noise but more expensive) | `10` |\n| focus | Depth focus, use it to shift the focal point (where the shadow is the sharpest) | `0` (the beginning) |\n"
  },
  {
    "path": "docs/guide/staging/sparkles.md",
    "content": "# Sparkles\n\n<DocsDemo>\n  <SparklesDemo />\n</DocsDemo>\n\n`<Sparkles />` makes sparkles on your geometry's vertices – optionally guided by a directional light.\n\n## Usage\n\n### Basic\n\n<<< @/.vitepress/theme/components/SparklesDemo.vue{3,11}\n\n### With TresDirectionalLight\n\nBy default, sparkles appear on the up-facing vertices. However, you can pass a directional light to the component. Moving the directional light will cause \"lit\" vertices to emit sparkles.\n\n<DocsDemo>\n  <SparklesDirectionalLightDemo />\n</DocsDemo>\n\n<<< @/.vitepress/theme/components/SparklesDirectionalLightDemo.vue{6,19-24,27}\n\n### Sequences\n\nAll props beginning with `:sequence-` are used to define how a particle changes as it progresses [(See also: Mixes)](#mixes). `:sequence-` props are of the type `Gradient<T>`, which can be any one of:\n\n* `T`: a single value\n* `[T, T, T, ...]`: an evenly distributed series of values\n* `[[number, T], [number, T], ...]`: an unevently distributed series of values, where `number` is a gradient \"stop\" from `0` to `1`.\n\nFor example, all of these are acceptable values for `Gradient<TresColor>`:\n\n* `'red'`\n* `['red', 'blue', 'green']`\n* `[[0.1, 'red'], [0.25, 'blue'], [0.5, 'green']]`\n\n<DocsDemo>\n  <SparklesSequenceDemo />\n</DocsDemo>\n\n<<< @/.vitepress/theme/components/SparklesSequenceDemo.vue{12-16}\n\n### Mixes\n\nAll props beginning with `:mix-` allow you to specify how a particle \"progresses\" through a corresponding `:sequence-` prop. E.g., `:mix-alpha` affects `:sequence-alpha`.\n\n* If the `:mix-` prop is `0.0`, 'progress' through the `:sequence-` is determined entirely by the light shining on the surface of the sparkling mesh.[<sup>1</sup>](#precisely)\n* If the `:mix-` prop is `1.0`, 'progress' through the `:sequence-` is determined entirely by the particle's lifetime.\n\n<small><a id=\"precisely\">1)</a> More precisely, the value is determined by the dot product of the `directionalLight`'s inverted normalized position and each of the sparkling mesh's vertex normals.</small>\n\n<DocsDemo>\n  <SparklesMixDemo />\n</DocsDemo>\n\n<<< @/.vitepress/theme/components/SparklesMixDemo.vue{9-11,35-39}\n\n## Props\n\n<table><thead><tr><th>Name</th><th>Description</th></tr></thead><tbody><tr><td><strong>map</strong></td><td>Type: <code>Texture | string</code><br>Default: <code><span>'https://raw.githubusercontent.com/Tresjs/asset...</span></code><br><br>Texture or image path for individual sparkles<br>\n</td></tr><tr><td><strong>geometry</strong></td><td>Type: <code>Object3D | BufferGeometry</code><br>Default: <code>undefined</code><br><br>Vertices of the geometry will be used to emit sparkles. Geometry normals are used for sparkles' traveling direction and for responding to the directional light prop.<br>\n<ul>\n<li>If provided, the component will use the passed geometry.</li>\n<li>If no geometry is provided, the component will try to make a copy of the parent object's geometry.</li>\n<li>If no parent geometry exists, the component will create and use an IcosphereGeometry.</li>\n</ul>\n</td></tr><tr><td><strong>directionalLight</strong></td><td>Type: <code>Object3D</code><br>Default: <code>undefined</code><br><br>Particles \"light up\" when their normal \"faces\" the light. If no <code>directionalLight</code> is provided, the default \"up\" vector will be used.<br>\n</td></tr><tr><td><strong>lifetimeSec</strong></td><td>Type: <code>number</code><br>Default: <code>0.4</code><br><br>Particle lifetime in seconds<br>\n</td></tr><tr><td><strong>cooldownSec</strong></td><td>Type: <code>number</code><br>Default: <code>2.0</code><br><br>Particle cooldown in seconds – time between lifetime end and respawn<br>\n</td></tr><tr><td><strong>normalThreshold</strong></td><td>Type: <code>number</code><br>Default: <code>0.7</code><br><br>Number from 0-1 indicating how closely the particle needs to be faced towards the light to \"light up\". (Lower == more flexible)<br>\n</td></tr><tr><td><strong>noiseScale</strong></td><td>Type: <code>number</code><br>Default: <code>3.0</code><br><br>Scale of the noise period (lower == more slowly cycling noise)<br>\n</td></tr><tr><td><strong>scaleNoise</strong></td><td>Type: <code>number</code><br>Default: <code>1.0</code><br><br>Noise coefficient applied to particle scale<br>\n</td></tr><tr><td><strong>offsetNoise</strong></td><td>Type: <code>number</code><br>Default: <code>0.1</code><br><br>Noise coefficient applied to particle offset<br>\n</td></tr><tr><td><strong>lifetimeNoise</strong></td><td>Type: <code>number</code><br>Default: <code>0.0</code><br><br>Noise coefficient applied to particle lifetime<br>\n</td></tr><tr><td><strong>size</strong></td><td>Type: <code>number</code><br>Default: <code>1.0</code><br><br>Particle scale multiplier<br>\n</td></tr><tr><td><strong>alpha</strong></td><td>Type: <code>number</code><br>Default: <code>1.0</code><br><br>Opacity multiplier<br>\n</td></tr><tr><td><strong>offset</strong></td><td>Type: <code>number</code><br>Default: <code>1.0</code><br><br>Offset multiplier<br>\n</td></tr><tr><td><strong>surfaceDistance</strong></td><td>Type: <code>number</code><br>Default: <code>1.0</code><br><br>Surface distance multiplier<br>\n</td></tr><tr><td><strong>sequenceColor</strong></td><td>Type: <code>Gradient&lt;TresColor&gt;</code><br>Default: <code>[[0.7, '#82dbc5'], [0.8, '#fbb03b']]</code><br><br>'<em>Sequence' props: specify how a particle changes as it \"progresses\". See also \"mix</em>\" props.<br>\nColor sequence as particles progress<br>\n</td></tr><tr><td><strong>sequenceAlpha</strong></td><td>Type: <code>Gradient&lt;number&gt;</code><br>Default: <code>[[0.0, 0.0], [0.10, 1.0], [0.5, 1.0], [0.9, 0.0]]</code><br><br>Opacity sequence as particles progress<br>\n</td></tr><tr><td><strong>sequenceOffset</strong></td><td>Type: <code>Gradient&lt;[number, number, number]&gt;</code><br>Default: <code>[0.0, 0.0, 0.0]</code><br><br>Distance sequence as particles progress<br>\n</td></tr><tr><td><strong>sequenceNoise</strong></td><td>Type: <code>Gradient&lt;[number, number, number]&gt;</code><br>Default: <code>[0.1, 0.1, 0.1]</code><br><br>Noise sequence as particles progress<br>\n</td></tr><tr><td><strong>sequenceSize</strong></td><td>Type: <code>Gradient&lt;number&gt;</code><br>Default: <code>[0.0, 1.0]</code><br><br>Size sequence as particles progress<br>\n</td></tr><tr><td><strong>sequenceSurfaceDistance</strong></td><td>Type: <code>Gradient&lt;number&gt;</code><br>Default: <code>[0.05, 0.08, 0.1]</code><br><br>Distance from surface (along normal) as particles progress<br>\n</td></tr><tr><td><strong>mixColor</strong></td><td>Type: <code>number</code><br>Default: <code>0.5</code><br><br>'mix*' props: A particle \"progresses\" with a mix of two factors:<br>\n<ul>\n<li>its normal \"facing\" the directionalLight</li>\n<li>its lifetime</li>\n</ul>\n'mix*' props specify the relationship between the two factors.<br>\nHow is a particle's progress for color calculated? (0: normal, 1: particle lifetime)<br>\n</td></tr><tr><td><strong>mixAlpha</strong></td><td>Type: <code>number</code><br>Default: <code>1.</code><br><br>How is a particle's progress for alpha calculated? (0: normal, 1: particle lifetime)<br>\n</td></tr><tr><td><strong>mixOffset</strong></td><td>Type: <code>number</code><br>Default: <code>1.</code><br><br>How is a particle's progress for offset calculated? (0: normal, 1: particle lifetime)<br>\n</td></tr><tr><td><strong>mixSize</strong></td><td>Type: <code>number</code><br>Default: <code>0.</code><br><br>How is a particle's progress for size calculated? (0: normal, 1: particle lifetime)<br>\n</td></tr><tr><td><strong>mixSurfaceDistance</strong></td><td>Type: <code>number</code><br>Default: <code>1.</code><br><br>How is a particle's progress for surface distance calculated? (0: normal, 1: particle lifetime)<br>\n</td></tr><tr><td><strong>mixNoise</strong></td><td>Type: <code>number</code><br>Default: <code>1.</code><br><br>How is a particle's progress for lifetime calculated? (0: normal, 1: particle lifetime)<br>\n</td></tr><tr><td><strong>blending</strong></td><td>Type: <code>Blending</code><br>Default: <code>AdditiveBlending</code><br><br>Material blending<br>\n</td></tr><tr><td><strong>transparent</strong></td><td>Type: <code>boolean</code><br>Default: <code>true</code><br><br>Material transparency<br>\n</td></tr><tr><td><strong>depthWrite</strong></td><td>Type: <code>boolean</code><br>Default: <code>false</code><br><br>Material depth write<br>\n</td></tr></tbody></table>5-39\n"
  },
  {
    "path": "docs/guide/staging/stage.md",
    "content": "# Stage\n\n<DocsDemo>\n  <StageDemo />\n</DocsDemo>\n\nThis component creates a \"stage\" for your models. It sets up:\n\n* model lighting\n* ground shadows\n* zoom to fit\n* environment\n\n::: info\nIf you are using other camera controls, be sure to make them the 'default'.\n```vue\n<OrbitControls make-default />\n```\n:::\n\n::: info\nIf you are using `shadows=\"accumulative\"`, enable shadows on your canvas.\n```vue\n<TresCanvas shadows />\n```\n\nAnd on your objects.\n\n```vue\n<TresMesh cast-shadow />\n  ...\n</TresMesh>\n```\n:::\n\n## Usage\n\n<<< @/.vitepress/theme/components/StageDemo.vue\n\n## Props\n\n```ts\ninterface StageProps {\n  /** Lighting setup, default: \"rembrandt\" */\n  lighting?:\n    | null | undefined | false\n    | 'rembrandt'\n    | 'portrait'\n    | 'upfront'\n    | 'soft'\n    | { main: [x: number, y: number, z: number], fill: [x: number, y: number, z: number] }\n  /** Controls the ground shadows, default: \"contact\" */\n  shadows?: boolean | 'contact' | 'accumulative' | StageShadows\n  /** Optionally wraps and thereby centers the models using <Bounds>, can also be a camera offset, default: true */\n  adjustCamera?: boolean | number\n  /** The default environment, default: \"city\" */\n  environment?: string | Partial<EnvironmentOptions> | null\n  /** Lighting intensity, `0` removes lights, default: 0.5 */\n  intensity?: number\n  /** To adjust alignment, default: undefined */\n  align?: Partial<AlignProps>\n}\n\ntype StageShadows = Partial<AccumulativeShadowsProps> &\n  Partial<RandomizedLightsProps> &\n  Partial<ContactShadowsProps> & {\n    type: 'contact' | 'accumulative'\n    /** Shadow plane offset, default: 0 */\n    offset?: number\n    /** Shadow bias, default: -0.0001 */\n    bias?: number\n    /** Shadow normal bias, default: 0 */\n    normalBias?: number\n    /** Shadow map size, default: 1024 */\n    size?: number\n  }\n```\n"
  },
  {
    "path": "docs/guide/staging/stars.md",
    "content": "# Stars\n\n`<Stars />` is a component that renders a stars in the sky of your scene. It is an abstraction that use Points, PointsMaterial and BufferGeometry to create a beautiful stars effect\n\n<DocsDemo>\n  <StarsDemo />\n</DocsDemo>\n\n## Usage\n\nYou can use `<Stars />` component without passing any props,\n\n```vue\n<template>\n  <TresCanvas>\n    ...\n    <Stars />\n    ...\n  </TresCanvas>\n</template>\n```\n\nBut still if you want you can tweak the props to find the best setup for you.\n\n<<< @/.vitepress/theme/components/StarsDemo.vue{4,15-22}\n\nNotice that you can pass a texture as an alphaMap to personalize the star shape\n\n```vue\n<template>\n  <TresCanvas>\n    ...\n    <Stars\n      :radius=\"50\"\n      :depth=\"20\"\n      :count=\"3000\"\n      :alpha-map=\"alphaMap\"\n    />\n    ...\n  </TresCanvas>\n</template>\n```\n## Props\n\n| Prop               | Description                                                            | Default |\n| :----------------- | :--------------------------------------------------------------------- | ------- |\n| **size**           | The size of the stars                        |   0.1      |\n| **sizeAttenuation**           | keep the same size regardless distance.|   true      |\n| **transparent**           | show transparency on the stars texture                                 | true     |\n| **alphaTest**         | enables the WebGL to know when not to render the pixeltext.                                                | 0.01     |\n| **alphaMap**  | texture of the stars | null      |\n| **count**   | number of stars      | 5000    |\n| **depth** | depth of star's shape                         | 50    |\n| **radius**      | Radius of star's shape                            | 100    |\n"
  },
  {
    "path": "docs/guide/staging/use-environment.md",
    "content": "# UseEnvironment\n\n<DocsDemo>\n  <EnvironmentDemo />\n</DocsDemo>\n\n`useEnvironment` composable that automatically sets up a global cubemap, which affects the default `scene.environment`, and optionally `scene.background`.\n\nIt uses the [CubeTextureLoader](https://threejs.org/docs/#api/en/loaders/CubeTextureLoader) to load the cubemap\n\n## Usage\n\n::: warning\n`UseEnvironment` needs to be wrapped by a Suspense component\n:::\n\n```ts\nimport { useEnvironment } from '@tresjs/cientos'\n\nconst texture = await useEnvironment({\n  files: [\n    '/textures/environmentMaps/0/px.jpg',\n    '/textures/environmentMaps/0/nx.jpg',\n    '/textures/environmentMaps/0/py.jpg',\n    '/textures/environmentMaps/0/ny.jpg',\n    '/textures/environmentMaps/0/pz.jpg',\n    '/textures/environmentMaps/0/nz.jpg',\n  ],\n  path: '',\n  encoding: SRGBColorSpace,\n})\n```\n\nThen you can use the `texture` in your scene:\n\n```vue{3}\n<TresMesh>\n  <TresSphereGeometry />\n  <TresMeshStandardMaterial :map=\"texture\" />\n</TresMesh>\n```\n\nYou can also pass the `.hdr` file directly\n\n```ts\nimport { useEnvironment } from '@tresjs/cientos'\n\nconst texture = await useEnvironment({\n  files: '/sunset.hdr',\n  path: '',\n  encoding: SRGBColorSpace,\n})\n```\n\n## Options\n\n| Name           | Type       | Default                                                                          | Description                                                                 |\n| :------------- | ---------- | -------------------------------------------------------------------------------- | --------------------------------------------------------------------------- |\n| **files**      | `Array`    | `undefined`                                                                      | Array of 6 urls to images, one for each side of the CubeTexture. or and HDR |\n| **path**       | `boolean`  | `false`                                                                          | Path to the environment map files.                                          |\n| **encoding**   | `Encoding` | `SRGBColorSpace` for an array of files and `LinearEncoding` for a single texture | Encoding of the environment map.                                            |\n| **background** | `boolean`  | `false`                                                                          | If `true` the texture will be used as the scene background.                 |\n| **blur**       | `number`   | `0`                                                                              | Blur factor between 0 and 1. (only works with three 0.146 and up)           |\n| **preset**     | `string`   | `undefined`                                                                      | Preset environment map.                                                     |\n| **backgroundIntensity** | `number` | `1` | Intensity of the background. |\n| **environmentIntensity** | `number` | `1` | Intensity of the environment. |\n| **backgroundRotation** | `VectorFlexibleParams` | `[0, 0, 0]` | Rotation of the background. |\n| **environmentRotation** | `VectorFlexibleParams` | `[0, 0, 0]` | Rotation of the environment. |\n"
  },
  {
    "path": "docs/index.md",
    "content": "---\n# https://vitepress.dev/reference/default-theme-home-page\nlayout: home\n\nhero:\n  name: \"Cientos\"\n  text: \"Ready-made abstractions for TresJS\"\n  tagline: Extending helpers and composables using Three addons.\n  actions:\n    - theme: brand\n      text: Get Started\n      link: /guide/\n    - theme: alt\n      text: Why Tres?\n      link: https://tresjs.org/guide/#motivation\n\nfeatures:\n  - icon: 🦾\n    title: three-stdlib\n    details: Because the ThreeJS addons repo structure is... daunting\n  - icon: 🦄\n    title: Extendable\n    details: You want to create a fancy shader material component? Submit a PR 🤗\n  - icon: 💛\n    title: Community-Driven\n    details: Benefits from the active and growing Vue TresJS community.\n---\n"
  },
  {
    "path": "docs/markdown-examples.md",
    "content": "# Markdown Extension Examples\n\nThis page demonstrates some of the built-in markdown extensions provided by VitePress.\n\n## Syntax Highlighting\n\nVitePress provides Syntax Highlighting powered by [Shiki](https://github.com/shikijs/shiki), with additional features like line-highlighting:\n\n**Input**\n\n````\n```js{4}\nexport default {\n  data () {\n    return {\n      msg: 'Highlighted!'\n    }\n  }\n}\n```\n````\n\n**Output**\n\n```js{4}\nexport default {\n  data () {\n    return {\n      msg: 'Highlighted!'\n    }\n  }\n}\n```\n\n## Custom Containers\n\n**Input**\n\n```md\n::: info\nThis is an info box.\n:::\n\n::: tip\nThis is a tip.\n:::\n\n::: warning\nThis is a warning.\n:::\n\n::: danger\nThis is a dangerous warning.\n:::\n\n::: details\nThis is a details block.\n:::\n```\n\n**Output**\n\n::: info\nThis is an info box.\n:::\n\n::: tip\nThis is a tip.\n:::\n\n::: warning\nThis is a warning.\n:::\n\n::: danger\nThis is a dangerous warning.\n:::\n\n::: details\nThis is a details block.\n:::\n\n## More\n\nCheck out the documentation for the [full list of markdown extensions](https://vitepress.dev/guide/markdown).\n"
  },
  {
    "path": "docs/package.json",
    "content": "{\n  \"name\": \"docs\",\n  \"type\": \"module\",\n  \"version\": \"0.0.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"dev\": \"vitepress dev\",\n    \"build\": \"vitepress build\",\n    \"preview\": \"vitepress preview\"\n  },\n  \"dependencies\": {\n    \"@tresjs/cientos\": \"workspace:^\"\n  },\n  \"devDependencies\": {\n    \"@tresjs/leches\": \"^0.14.0\",\n    \"markdown-it\": \"^14.0.0\",\n    \"unocss\": \"^0.65.1\",\n    \"vite-svg-loader\": \"^5.1.0\"\n  }\n}\n"
  },
  {
    "path": "docs/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"esnext\",\n    \"jsx\": \"preserve\",\n    \"lib\": [\"DOM\", \"ESNext\"],\n    \"module\": \"esnext\",\n    \"moduleResolution\": \"node\",\n    \"resolveJsonModule\": true,\n    \"types\": [\"vite/client\"],\n    \"strict\": true,\n    \"noUnusedLocals\": true,\n    \"esModuleInterop\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"skipLibCheck\": true\n  },\n  \"exclude\": [\"dist\", \"node_modules\"]\n}\n"
  },
  {
    "path": "docs/vite.config.ts",
    "content": "import Unocss from 'unocss/vite'\nimport Components from 'unplugin-vue-components/vite'\nimport { defineConfig } from 'vite'\nimport svgLoader from 'vite-svg-loader'\n\nexport default defineConfig({\n  plugins: [\n    svgLoader(),\n    Unocss(),\n    Components({\n      // allow auto load markdown components under `.vitepress/theme/components`\n      dirs: ['.vitepress/theme/components'],\n      extensions: ['vue', 'md'],\n      // allow auto import and register components used in markdown\n      include: [/\\.vue$/, /\\.vue\\?vue/, /\\.md$/],\n      dts: 'components.d.ts',\n    }),\n  ],\n})\n"
  },
  {
    "path": "eslint.config.js",
    "content": "import { tresLintConfig } from '@tresjs/eslint-config'\n\nexport default tresLintConfig({\n  rules: {\n    // TODO: temporary fix for Error while loading rule 'jsonc/no-useless-escape': Cannot read properties of undefined (reading 'allowRegexCharacters')\n    'jsonc/no-useless-escape': 'off',\n  },\n})\n"
  },
  {
    "path": "netlify.toml",
    "content": "[build]\npublish = \"docs/.vitepress/dist\"\ncommand = \"pnpm run build && pnpm docs:build\"\n\n[build.environment]\nNODE_VERSION = \"22\"\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"@tresjs/cientos\",\n  \"type\": \"module\",\n  \"version\": \"5.0.0\",\n  \"packageManager\": \"pnpm@10.17.0\",\n  \"description\": \"Collection of useful helpers and fully functional, ready-made abstractions for Tres\",\n  \"author\": \"Alvaro Saburido <hola@alvarosaburido.dev> (https://github.com/alvarosabu/)\",\n  \"license\": \"MIT\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/Tresjs/cientos.git\"\n  },\n  \"keywords\": [\n    \"vue\",\n    \"3d\",\n    \"threejs\",\n    \"three\",\n    \"threejs-vue\",\n    \"composables\"\n  ],\n  \"maintainers\": [\n    \"Alvaro Saburido (https://github.com/alvarosabu/)\",\n    \"Jaime Torrealba (https://github.com/JaimeTorrealba)\",\n    \"Andre Tchen (https://github.com/andretchen0)\"\n  ],\n  \"sideEffects\": false,\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/index.d.ts\",\n      \"import\": \"./dist/trescientos.js\"\n    },\n    \"./core\": {\n      \"types\": \"./dist/core/index.d.ts\"\n    },\n    \"./*\": \"./*\"\n  },\n  \"main\": \"./dist/trescientos.js\",\n  \"module\": \"./dist/trescientos.js\",\n  \"types\": \"./dist/index.d.ts\",\n  \"files\": [\n    \"*.d.ts\",\n    \"dist\"\n  ],\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"scripts\": {\n    \"dev\": \"cd playground/vue && pnpm dev\",\n    \"dev:nuxt\": \"cd playground/nuxt && pnpm dev\",\n    \"build\": \"vite build\",\n    \"release\": \"release-it\",\n    \"lint\": \"eslint .\",\n    \"typecheck\": \"vue-tsc --noEmit\",\n    \"lint:fix\": \"eslint . --fix\",\n    \"docs:dev\": \"vitepress dev docs\",\n    \"docs:build\": \"vitepress build docs\",\n    \"docs:preview\": \"vitepress preview docs\"\n  },\n  \"peerDependencies\": {\n    \"@tresjs/core\": \">=5.0.0\",\n    \"three\": \">=0.133\",\n    \"vue\": \">=3.5.17\"\n  },\n  \"dependencies\": {\n    \"@vueuse/core\": \"^13.8.0\",\n    \"camera-controls\": \"^2.9.0\",\n    \"stats-gl\": \"^2.0.1\",\n    \"stats.js\": \"^0.17.0\",\n    \"three-custom-shader-material\": \"^5.4.0\",\n    \"three-stdlib\": \"^2.36.0\"\n  },\n  \"devDependencies\": {\n    \"@release-it/conventional-changelog\": \"^10.0.1\",\n    \"@tresjs/core\": \"5.0.0\",\n    \"@tresjs/eslint-config\": \"^1.4.0\",\n    \"@types/node\": \"^24.3.0\",\n    \"@types/three\": \"^0.180.0\",\n    \"@typescript-eslint/eslint-plugin\": \"^8.41.0\",\n    \"@typescript-eslint/parser\": \"^8.41.0\",\n    \"@vitejs/plugin-vue\": \"^6.0.1\",\n    \"eslint\": \"^9.34.0\",\n    \"eslint-plugin-vue\": \"^10.4.0\",\n    \"gsap\": \"^3.13.0\",\n    \"kolorist\": \"^1.8.0\",\n    \"pathe\": \"^2.0.3\",\n    \"release-it\": \"^19.0.4\",\n    \"rollup-plugin-analyzer\": \"^4.0.0\",\n    \"rollup-plugin-visualizer\": \"^6.0.3\",\n    \"three\": \"^0.180.0\",\n    \"typescript\": \"^5.8.3\",\n    \"unocss\": \"^66.1.2\",\n    \"vite\": \"^7.1.6\",\n    \"vite-plugin-banner\": \"^0.8.1\",\n    \"vite-plugin-dts\": \"4.5.4\",\n    \"vite-plugin-glsl\": \"^1.5.1\",\n    \"vite-svg-loader\": \"^5.1.0\",\n    \"vitepress\": \"1.6.4\",\n    \"vue-tsc\": \"^3.0.7\"\n  }\n}\n"
  },
  {
    "path": "playground/vue/.eslintrc-auto-import.json",
    "content": "{\n  \"globals\": {\n    \"Component\": true,\n    \"ComponentPublicInstance\": true,\n    \"ComputedRef\": true,\n    \"DirectiveBinding\": true,\n    \"EffectScope\": true,\n    \"ExtractDefaultPropTypes\": true,\n    \"ExtractPropTypes\": true,\n    \"ExtractPublicPropTypes\": true,\n    \"InjectionKey\": true,\n    \"MaybeRef\": true,\n    \"MaybeRefOrGetter\": true,\n    \"PropType\": true,\n    \"Ref\": true,\n    \"ShallowRef\": true,\n    \"Slot\": true,\n    \"Slots\": true,\n    \"VNode\": true,\n    \"WritableComputedRef\": true,\n    \"computed\": true,\n    \"createApp\": true,\n    \"customRef\": true,\n    \"defineAsyncComponent\": true,\n    \"defineComponent\": true,\n    \"effectScope\": true,\n    \"getCurrentInstance\": true,\n    \"getCurrentScope\": true,\n    \"getCurrentWatcher\": true,\n    \"h\": true,\n    \"inject\": true,\n    \"isProxy\": true,\n    \"isReactive\": true,\n    \"isReadonly\": true,\n    \"isRef\": true,\n    \"isShallow\": true,\n    \"markRaw\": true,\n    \"nextTick\": true,\n    \"onActivated\": true,\n    \"onBeforeMount\": true,\n    \"onBeforeUnmount\": true,\n    \"onBeforeUpdate\": true,\n    \"onDeactivated\": true,\n    \"onErrorCaptured\": true,\n    \"onMounted\": true,\n    \"onRenderTracked\": true,\n    \"onRenderTriggered\": true,\n    \"onScopeDispose\": true,\n    \"onServerPrefetch\": true,\n    \"onUnmounted\": true,\n    \"onUpdated\": true,\n    \"onWatcherCleanup\": true,\n    \"provide\": true,\n    \"reactive\": true,\n    \"readonly\": true,\n    \"ref\": true,\n    \"resolveComponent\": true,\n    \"shallowReactive\": true,\n    \"shallowReadonly\": true,\n    \"shallowRef\": true,\n    \"toRaw\": true,\n    \"toRef\": true,\n    \"toRefs\": true,\n    \"toValue\": true,\n    \"triggerRef\": true,\n    \"unref\": true,\n    \"useAttrs\": true,\n    \"useCssModule\": true,\n    \"useCssVars\": true,\n    \"useId\": true,\n    \"useModel\": true,\n    \"useSlots\": true,\n    \"useTemplateRef\": true,\n    \"watch\": true,\n    \"watchEffect\": true,\n    \"watchPostEffect\": true,\n    \"watchSyncEffect\": true\n  }\n}\n"
  },
  {
    "path": "playground/vue/.eslintrc.json",
    "content": "{\n  \"extends\": \"@tresjs/eslint-config-vue\",\n  \"rules\": {\n    \"no-console\": \"off\",\n    \"vue/attribute-hyphenation\": [2, \"always\", {\n      \"ignore\": [\n        \"shadow-mapSize-width\",\n        \"shadow-mapSize-height\",\n        \"distortionMap\",\n        \"material-uniforms-mieCoefficient-value\",\n        \"material-uniforms-mieDirectionalG-value\",\n        \"material-uniforms-sunPosition-value\"\n      ]\n    }]\n  }\n}\n"
  },
  {
    "path": "playground/vue/.gitignore",
    "content": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\npnpm-debug.log*\nlerna-debug.log*\n\nnode_modules\ndist\ndist-ssr\n*.local\n\n# Editor directories and files\n.vscode/*\n!.vscode/extensions.json\n.idea\n.DS_Store\n*.suo\n*.ntvs*\n*.njsproj\n*.sln\n*.sw?\n"
  },
  {
    "path": "playground/vue/.vscode/extensions.json",
    "content": "{\n  \"recommendations\": [\"Vue.volar\", \"Vue.vscode-typescript-vue-plugin\"]\n}\n"
  },
  {
    "path": "playground/vue/README.md",
    "content": "# Vue 3 + TypeScript + Vite\n\nThis template should help get you started developing with Vue 3 and TypeScript in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.\n\n## Recommended IDE Setup\n\n- [VS Code](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur) + [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin).\n\n## Type Support For `.vue` Imports in TS\n\nTypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin) to make the TypeScript language service aware of `.vue` types.\n\nIf the standalone TypeScript plugin doesn't feel fast enough to you, Volar has also implemented a [Take Over Mode](https://github.com/johnsoncodehk/volar/discussions/471#discussioncomment-1361669) that is more performant. You can enable it by the following steps:\n\n1. Disable the built-in TypeScript Extension\n   1. Run `Extensions: Show Built-in Extensions` from VSCode's command palette\n   2. Find `TypeScript and JavaScript Language Features`, right click and select `Disable (Workspace)`\n2. Reload the VSCode window by running `Developer: Reload Window` from the command palette.\n"
  },
  {
    "path": "playground/vue/auto-imports.d.ts",
    "content": "/* eslint-disable */\n/* prettier-ignore */\n// @ts-nocheck\n// noinspection JSUnusedGlobalSymbols\n// Generated by unplugin-auto-import\n// biome-ignore lint: disable\nexport {}\ndeclare global {\n  const EffectScope: typeof import('vue')['EffectScope']\n  const computed: typeof import('vue')['computed']\n  const createApp: typeof import('vue')['createApp']\n  const customRef: typeof import('vue')['customRef']\n  const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']\n  const defineComponent: typeof import('vue')['defineComponent']\n  const effectScope: typeof import('vue')['effectScope']\n  const getCurrentInstance: typeof import('vue')['getCurrentInstance']\n  const getCurrentScope: typeof import('vue')['getCurrentScope']\n  const h: typeof import('vue')['h']\n  const inject: typeof import('vue')['inject']\n  const isProxy: typeof import('vue')['isProxy']\n  const isReactive: typeof import('vue')['isReactive']\n  const isReadonly: typeof import('vue')['isReadonly']\n  const isRef: typeof import('vue')['isRef']\n  const markRaw: typeof import('vue')['markRaw']\n  const nextTick: typeof import('vue')['nextTick']\n  const onActivated: typeof import('vue')['onActivated']\n  const onBeforeMount: typeof import('vue')['onBeforeMount']\n  const onBeforeUnmount: typeof import('vue')['onBeforeUnmount']\n  const onBeforeUpdate: typeof import('vue')['onBeforeUpdate']\n  const onDeactivated: typeof import('vue')['onDeactivated']\n  const onErrorCaptured: typeof import('vue')['onErrorCaptured']\n  const onMounted: typeof import('vue')['onMounted']\n  const onRenderTracked: typeof import('vue')['onRenderTracked']\n  const onRenderTriggered: typeof import('vue')['onRenderTriggered']\n  const onScopeDispose: typeof import('vue')['onScopeDispose']\n  const onServerPrefetch: typeof import('vue')['onServerPrefetch']\n  const onUnmounted: typeof import('vue')['onUnmounted']\n  const onUpdated: typeof import('vue')['onUpdated']\n  const onWatcherCleanup: typeof import('vue')['onWatcherCleanup']\n  const provide: typeof import('vue')['provide']\n  const reactive: typeof import('vue')['reactive']\n  const readonly: typeof import('vue')['readonly']\n  const ref: typeof import('vue')['ref']\n  const resolveComponent: typeof import('vue')['resolveComponent']\n  const shallowReactive: typeof import('vue')['shallowReactive']\n  const shallowReadonly: typeof import('vue')['shallowReadonly']\n  const shallowRef: typeof import('vue')['shallowRef']\n  const toRaw: typeof import('vue')['toRaw']\n  const toRef: typeof import('vue')['toRef']\n  const toRefs: typeof import('vue')['toRefs']\n  const toValue: typeof import('vue')['toValue']\n  const triggerRef: typeof import('vue')['triggerRef']\n  const unref: typeof import('vue')['unref']\n  const useAttrs: typeof import('vue')['useAttrs']\n  const useCssModule: typeof import('vue')['useCssModule']\n  const useCssVars: typeof import('vue')['useCssVars']\n  const useId: typeof import('vue')['useId']\n  const useModel: typeof import('vue')['useModel']\n  const useSlots: typeof import('vue')['useSlots']\n  const useTemplateRef: typeof import('vue')['useTemplateRef']\n  const watch: typeof import('vue')['watch']\n  const watchEffect: typeof import('vue')['watchEffect']\n  const watchPostEffect: typeof import('vue')['watchPostEffect']\n  const watchSyncEffect: typeof import('vue')['watchSyncEffect']\n}\n// for type re-export\ndeclare global {\n  // @ts-ignore\n  export type { Component, Slot, Slots, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, ShallowRef, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue'\n  import('vue')\n}\n"
  },
  {
    "path": "playground/vue/components.d.ts",
    "content": "/* eslint-disable */\n// @ts-nocheck\n// Generated by unplugin-vue-components\n// Read more: https://github.com/vuejs/core/pull/3399\n// biome-ignore lint: disable\nexport {}\n\n/* prettier-ignore */\ndeclare module 'vue' {\n  export interface GlobalComponents {\n    AkuAku: typeof import('./src/components/gltf/BlenderCube.vue')['default']\n    BlenderCube: typeof import('./src/components/gltf/BlenderCube.vue')['default']\n    FboCube: typeof import('./src/components/FboCube.vue')['default']\n    Gltf: typeof import('./src/components/gltf/index.vue')['default']\n    GraphPane: typeof import('./src/components/GraphPane.vue')['default']\n    Jeep: typeof import('./src/components/fbx/Jeep.vue')['default']\n    ModelsDemo: typeof import('./src/components/ModelsDemo.vue')['default']\n    OverlayInfo: typeof import('./src/components/OverlayInfo.vue')['default']\n    RouterLink: typeof import('vue-router')['RouterLink']\n    RouterView: typeof import('vue-router')['RouterView']\n    StarsForTest: typeof import('./src/components/StarsForTest.vue')['default']\n  }\n}\n"
  },
  {
    "path": "playground/vue/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <link rel=\"icon\" type=\"image/svg+xml\" href=\"/cientos.svg\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>Cientos playground</title>\n  </head>\n  <body>\n    <div id=\"app\"></div>\n    <script type=\"module\" src=\"/src/main.ts\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "playground/vue/package.json",
    "content": "{\n  \"name\": \"playground\",\n  \"type\": \"module\",\n  \"version\": \"0.0.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"dev\": \"vite --host\",\n    \"build\": \"vue-tsc && vite build\",\n    \"preview\": \"vite preview\"\n  },\n  \"dependencies\": {\n    \"@tresjs/core\": \"5.0.0\",\n    \"vue-router\": \"^4.5.1\"\n  },\n  \"devDependencies\": {\n    \"@tresjs/leches\": \"^0.14.1\",\n    \"unplugin-auto-import\": \"^20.1.0\",\n    \"unplugin-vue-components\": \"^29.0.0\",\n    \"vite-plugin-glsl\": \"^1.5.1\",\n    \"vite-plugin-qrcode\": \"^0.3.0\",\n    \"vue-tsc\": \"^3.0.7\"\n  }\n}\n"
  },
  {
    "path": "playground/vue/src/App.vue",
    "content": "<script setup lang=\"ts\">\nimport { watch } from 'vue'\nimport { useRoute } from 'vue-router'\n\nconst route = useRoute()\nfunction setBodyClass(routeName: string) {\n  document.title = `Cientos Playground - ${routeName}`\n  document.body.className = routeName\n}\nwatch([route], () => setBodyClass(route.name?.toString() ?? ''))\n</script>\n\n<template>\n  <Suspense>\n    <router-view />\n  </Suspense>\n</template>\n"
  },
  {
    "path": "playground/vue/src/components/FboCube.vue",
    "content": "<script setup lang=\"ts\">\nimport { useFBO } from '@tresjs/cientos'\n\nconst fboTarget = useFBO({\n  depth: true,\n  width: 512,\n  height: 512,\n  settings: {\n    samples: 1,\n  },\n})\n</script>\n\n<template>\n  <TresMesh>\n    <TresBoxGeometry :args=\"[1, 1, 1]\" />\n\n    <TresMeshBasicMaterial\n      :color=\"0xFF8833\"\n      :map=\"fboTarget?.texture ?? null\"\n    />\n  </TresMesh>\n</template>\n"
  },
  {
    "path": "playground/vue/src/components/GraphPane.vue",
    "content": "<script lang=\"ts\" setup>\nimport { useRafFn } from '@vueuse/core'\nimport { ref } from 'vue'\nimport { useState } from '../composables/state'\n\nconst width = 160\nconst height = 40\nconst strokeWidth = 2\nconst updateInterval = 100 // Update interval in milliseconds\nconst topOffset = 0 // Offset from the top\n\nconst points = ref('')\nconst frameTimes = ref([])\nconst maxFrames = ref(width / strokeWidth)\n\nlet lastUpdateTime = performance.now()\n\nconst { renderingTimes } = useState()\n\nuseRafFn(({ timestamp }) => {\n  if (timestamp - lastUpdateTime >= updateInterval) {\n    lastUpdateTime = timestamp\n\n    frameTimes.value.push(renderingTimes?.value)\n    renderingTimes.value = 0\n\n    if (frameTimes.value.length > maxFrames.value) {\n      frameTimes.value.shift()\n    }\n\n    points.value = frameTimes.value\n      .map(\n        (value, index) =>\n          `${index * strokeWidth},${\n            height + topOffset - strokeWidth / 2 - (value * (height + topOffset - strokeWidth)) / 2\n          }`,\n      )\n      .join(' ')\n  }\n})\n</script>\n\n<template>\n  <div\n    class=\"absolute\n      left-2\n      top-2\n      flex\n      px-4\n      py-1\n      justify-between\n      gap-4\n      items-center\n      mb-2\n      z-10\n      bg-white\n      dark:bg-dark\n      shadow-xl\n      rounded\n      border-4\n      border-solid\n      bg-primary\n      border-primary\n      pointer-events-none\n      overflow-hidden\"\n  >\n    <label class=\"text-secondary text-xs w-1/3\">Rendering Activity</label>\n\n    <div\n      class=\"\n        bg-gray-100\n        dark:bg-gray-600\n        relative\n        w-2/3\n        p-1\n        rounded\n        text-right\n        text-xs\n        focus:border-gray-200\n        outline-none\n        border-none\n        font-sans\n      \"\n    >\n      <svg\n        :width=\"width\"\n        :height=\"height\"\n        xmlns=\"http://www.w3.org/2000/svg\"\n        fill=\"none\"\n      >\n        <polyline\n          :points=\"points\"\n          stroke=\"lightgray\"\n          :stroke-width=\"strokeWidth\"\n          stroke-linecap=\"round\"\n          stroke-linejoin=\"round\"\n        />\n      </svg>\n    </div>\n  </div>\n</template>\n"
  },
  {
    "path": "playground/vue/src/components/OverlayInfo.vue",
    "content": "<template>\n  <div class=\"overlay-info\">\n    <slot></slot>\n  </div>\n</template>\n\n<style scoped>\n.overlay-info {\n  position: fixed;\n  top: 0;\n  left: 0;\n  margin: 10px;\n  padding: 16px;\n  max-width: 400px;\n  z-index: 1000;\n  font-family:\n    ui-sans-serif,\n    system-ui,\n    -apple-system,\n    BlinkMacSystemFont,\n    'Segoe UI',\n    Roboto,\n    'Helvetica Neue',\n    Arial,\n    'Noto Sans',\n    sans-serif,\n    'Apple Color Emoji',\n    'Segoe UI Emoji',\n    'Segoe UI Symbol',\n    'Noto Color Emoji';\n  font-size: small;\n  background-color: white;\n  border-radius: 6px;\n  overflow: auto;\n}\n</style>\n"
  },
  {
    "path": "playground/vue/src/components/StarsForTest.vue",
    "content": "<script setup lang=\"ts\">\nimport { Stars } from '@tresjs/cientos'\nimport { useLoop } from '@tresjs/core'\nimport { shallowRef } from 'vue'\nimport type { Points } from 'three'\n\nconst star = shallowRef()\n\nconst options = reactive({\n  size: 4,\n  sizeAttenuation: true,\n  count: 50000,\n  depth: 50,\n  radius: 1000,\n})\n\nconst { onBeforeRender } = useLoop()\n\nonBeforeRender(() => {\n  (star.value.instance as Points).rotation.y += 0.003\n})\n</script>\n\n<template>\n  <Stars\n    ref=\"star\"\n    :radius=\"options.radius\"\n    :depth=\"options.depth\"\n    :count=\"options.count\"\n    :size=\"options.size\"\n    :size-attenuation=\"options.sizeAttenuation\"\n  />\n</template>\n"
  },
  {
    "path": "playground/vue/src/components/fbx/Jeep.vue",
    "content": "<script setup lang=\"ts\">\nimport { useFBX } from '@tresjs/cientos'\nimport { type Group, Mesh } from 'three'\n\nconst model = await useFBX(\n  'https://raw.githubusercontent.com/Tresjs/assets/main/models/fbx/low-poly-truck/Jeep_done.fbx',\n)\n\nconst truckRef = shallowRef<Group | null>(null)\n\nwatch(truckRef, (truck) => {\n  if (truck) {\n    truck.scale.set(0.01, 0.01, 0.01)\n    truck.position.set(0, -1.6, 0)\n    truck.rotation.y = -Math.PI * 0.5\n    truck.traverse((child) => {\n      if (child instanceof Mesh) {\n        child.castShadow = true\n      }\n    })\n  }\n})\n</script>\n\n<template>\n  <primitive ref=\"truckRef\" :object=\"model\" />\n</template>\n"
  },
  {
    "path": "playground/vue/src/components/gltf/BlenderCube.vue",
    "content": "<script setup lang=\"ts\">\nimport { useGLTF } from '@tresjs/cientos'\nimport type { TresObject } from '@tresjs/core'\nimport { computed, shallowRef } from 'vue'\n\nconst { nodes } = useGLTF(\n  'https://raw.githubusercontent.com/Tresjs/assets/main/models/gltf/blender-cube.glb',\n  { draco: true },\n)\n\nconst modelRef = shallowRef<TresObject | null>(null)\n\nconst model = computed(() => nodes.value?.BlenderCube)\n</script>\n\n<template>\n  <primitive v-if=\"model\" ref=\"modelRef\" :object=\"model\" />\n</template>\n"
  },
  {
    "path": "playground/vue/src/composables/state.ts",
    "content": "import { reactive, toRefs } from 'vue'\n\nconst state = reactive({\n  renderingTimes: 0,\n})\nexport function useState() {\n  return {\n    ...toRefs(state),\n\n  }\n}\n"
  },
  {
    "path": "playground/vue/src/main.ts",
    "content": "import { createApp } from 'vue'\nimport App from './App.vue'\nimport { router } from './router'\nimport './style.css'\nimport 'uno.css'\n\nconst app = createApp(App)\n\napp.use(router)\n\napp.mount('#app')\n"
  },
  {
    "path": "playground/vue/src/pages/abstractions/AnimatedSpriteDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { AnimatedSprite, Box, OrbitControls } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { TresLeches, useControls } from '@tresjs/leches'\nimport { BasicShadowMap, NoToneMapping, SRGBColorSpace } from 'three'\nimport { degToRad } from 'three/src/math/MathUtils.js'\nimport { ref, watch } from 'vue'\nimport { useState } from '../../composables/state'\nimport type { Atlasish } from '../../../../../src/core/abstractions/AnimatedSprite/Atlas'\nimport '@tresjs/leches/styles'\n\nconst ASSETS_URL = 'https://raw.githubusercontent.com/andretchen0/tresjs_assets/'\n  + '462ad0f669f78d2c5ed7007b5134b419f646efad/textures/animated-sprite/'\n\nconst gl = {\n  clearColor: '#82DBC5',\n  shadows: true,\n  alpha: false,\n  shadowMapType: BasicShadowMap,\n  outputColorSpace: SRGBColorSpace,\n  toneMapping: NoToneMapping,\n}\n\nconst { fps, animation, definitions, flipX, loop, paused, reversed, resetOnEnd, asSprite, centerX, centerY, scale, rotationX, rotationY, rotationZ, position } = useControls({\n  fps: { value: 10, min: 0, max: 120, step: 1 },\n  animation: { label: 'Animation', value: 'idle', options: ['idle', 'walk', 'blink'] },\n  definitions: { label: 'Definitions', value: '{}', options: ['{}', '{\"idle\":\"0(10),1-5\"}'] },\n  flipX: false,\n  loop: true,\n  paused: false,\n  reversed: false,\n  resetOnEnd: false,\n  asSprite: false,\n  centerX: { value: 0.5, min: 0, max: 1, step: 0.01 },\n  centerY: { value: 0.5, min: 0, max: 1, step: 0.01 },\n  scale: { value: 1, min: 0.1, max: 4, step: 0.01 },\n  rotationX: { value: 0, step: 1, min: -360, max: 360 },\n  rotationY: { value: 0, step: 1, min: -360, max: 360 },\n  rotationZ: { value: 0, step: 1, min: -360, max: 360 },\n  position: { value: [0, 0, 0] },\n})\n\nconst lastFrame = ref('-')\nconst lastEnd = ref('-')\nconst lastLoop = ref('-')\nconst defsParsed = ref(JSON.parse(definitions.value.value))\n\nwatch(() => definitions.value.value, () => {\n  defsParsed.value = JSON.parse(definitions.value.value)\n})\n\nconst centerDemoAtlas: Atlasish = { frames: [] }\nconst centerDemoImgData = (() => {\n  const NUM_ROWS_COLS = 32\n  const rects: { x: number, y: number, w: number, h: number }[] = []\n  let h = 1\n  for (let r = 0; r < NUM_ROWS_COLS; r += h) {\n    let w = 1\n    for (let c = 0; c < NUM_ROWS_COLS; c += w) {\n      if (Math.random() > 0.6) {\n        w++\n      }\n      if (c + w >= NUM_ROWS_COLS) {\n        w = NUM_ROWS_COLS - c\n      }\n      if (Math.random() > 0.9) {\n        h++\n      }\n      if (r + h >= NUM_ROWS_COLS) {\n        h = NUM_ROWS_COLS - r\n      }\n      rects.push({ x: c, y: r, w, h })\n    }\n  }\n\n  const canvas = document.createElement('canvas')\n  const IMG_SIZE = 2048\n  const COL_SIZE = IMG_SIZE / NUM_ROWS_COLS\n  const ROW_SIZE = IMG_SIZE / NUM_ROWS_COLS\n  canvas.width = IMG_SIZE\n  canvas.height = IMG_SIZE\n  document.body.append(canvas)\n  const ctx = canvas.getContext('2d')!\n  const EDGE_center_SIZE = 6\n  const CENTER_center_SIZE = COL_SIZE\n  rects.forEach((rect, i) => {\n    const frame = { x: rect.x * COL_SIZE, y: rect.y * ROW_SIZE, w: rect.w * COL_SIZE, h: rect.h * ROW_SIZE }\n    const { x, y, w, h } = frame\n    centerDemoAtlas.frames.push({ filename: `rect_${i.toString().padStart(4, '0')}`, frame })\n    ctx.fillStyle = `hsl(${360 * i / rects.length}, 100%, 50%)`\n    ctx.fillRect(x, y, w, h)\n\n    ctx.fillStyle = 'rgba(0, 0, 0, 0.5)'\n    ctx.fillRect(\n      x + w * 0.5 - CENTER_center_SIZE * 0.5,\n      y + h * 0.5 - CENTER_center_SIZE * 0.5,\n      CENTER_center_SIZE,\n      CENTER_center_SIZE,\n    )\n\n    ctx.fillStyle = '#FFF'\n    ctx.textAlign = 'center'\n    ctx.font = '12px monospace'\n    ctx.textBaseline = 'middle'\n    ctx.fillText(`Frame ${i}`, x + w * 0.5, y + h * 0.5)\n\n    ctx.fillStyle = '#FFF'\n    ctx.fillRect(x, y, EDGE_center_SIZE, EDGE_center_SIZE)\n    ctx.fillRect(x + w * 0.5 - EDGE_center_SIZE * 0.5, y, EDGE_center_SIZE, EDGE_center_SIZE)\n    ctx.fillRect(x + w - EDGE_center_SIZE, y, EDGE_center_SIZE, EDGE_center_SIZE)\n\n    ctx.fillRect(x, y + h * 0.5 - EDGE_center_SIZE * 0.5, EDGE_center_SIZE, EDGE_center_SIZE)\n    ctx.fillRect(x + w - EDGE_center_SIZE, y + h * 0.5 - EDGE_center_SIZE * 0.5, EDGE_center_SIZE, EDGE_center_SIZE)\n\n    ctx.fillRect(x, y + h - EDGE_center_SIZE, EDGE_center_SIZE, EDGE_center_SIZE)\n    ctx.fillRect(x + w * 0.5 - EDGE_center_SIZE * 0.5, y + h - EDGE_center_SIZE, EDGE_center_SIZE, EDGE_center_SIZE)\n    ctx.fillRect(x + w - EDGE_center_SIZE, y + h - EDGE_center_SIZE, EDGE_center_SIZE, EDGE_center_SIZE)\n  })\n  const imgData = canvas.toDataURL()\n  canvas.parentElement?.removeChild(canvas)\n  return imgData\n})()\n\nconst { renderingTimes } = useState()\n\nfunction onRender() {\n  renderingTimes.value = 1\n}\n</script>\n\n<template>\n  <TresLeches />\n  <GraphPane />\n  <div style=\"position:absolute; top:0; z-index:1; font: 10px sans-serif; padding:10px;\">\n    <p>@frame: {{ lastFrame }}</p>\n    <p>@end: {{ lastEnd }}</p>\n    <p>@loop: {{ lastLoop }}</p>\n  </div>\n  <TresCanvas v-bind=\"gl\" render-mode=\"on-demand\" @render=\"onRender\">\n    <TresPerspectiveCamera :position=\"[11, 11, 11]\" />\n    <OrbitControls />\n    <TresGroup :position=\"[0, 0, -4]\">\n      <Suspense>\n        <AnimatedSprite\n          :image=\"centerDemoImgData\"\n          :atlas=\"centerDemoAtlas\"\n          animation=\"rect\"\n          :flip-x=\"flipX.value\"\n          :fps=\"fps.value\"\n          :loop=\"loop.value\"\n          :reset-on-end=\"resetOnEnd.value\"\n          :as-sprite=\"asSprite.value\"\n          :center=\"[centerX.value, centerY.value]\"\n          :reversed=\"reversed.value\"\n          :scale=\"scale.value\"\n          :paused=\"paused.value\"\n          :position=\"[position.value[0], position.value[1], position.value[2]]\"\n          :rotation=\"[degToRad(rotationX.value), degToRad(rotationY.value), degToRad(rotationZ.value)]\"\n        >\n          <TresGroup :scale=\"0.5\">\n            <Box\n              :scale=\"[1, 0.06, 0.06]\"\n              color=\"red\"\n            />\n            <Box\n              :scale=\"[0.06, 1, 0.06]\"\n              color=\"blue\"\n            />\n            <Box\n              :scale=\"[0.06, 0.06, 1]\"\n              color=\"green\"\n            />\n          </TresGroup>\n        </AnimatedSprite>\n      </Suspense>\n    </TresGroup>\n    <TresGroup :position=\"[4, 0, 0]\">\n      <Suspense>\n        <AnimatedSprite\n          :image=\"`${ASSETS_URL}namedAnimationsTexture.png`\"\n          :atlas=\"`${ASSETS_URL}namedAnimationsAtlas.json`\"\n          animation=\"yes\"\n          :flip-x=\"flipX.value\"\n          :fps=\"fps.value\"\n          :loop=\"loop.value\"\n          :reset-on-end=\"resetOnEnd.value\"\n          :as-sprite=\"asSprite.value\"\n          :center=\"[centerX.value, centerY.value]\"\n          :reversed=\"reversed.value\"\n          :scale=\"scale.value\"\n          :paused=\"paused.value\"\n          :position=\"[position.value[0], position.value[1], position.value[2]]\"\n          :rotation=\"[degToRad(rotationX.value), degToRad(rotationY.value), degToRad(rotationZ.value)]\"\n        />\n      </Suspense>\n    </TresGroup>\n    <TresGroup :position=\"[-4, 0, 0]\">\n      <Suspense>\n        <AnimatedSprite\n          :image=\"`${ASSETS_URL}textureWithoutAtlas.png`\"\n          :atlas=\"16\"\n          :animation=\"[0, 15]\"\n          :flip-x=\"flipX.value\"\n          :fps=\"fps.value\"\n          :loop=\"loop.value\"\n          :reset-on-end=\"resetOnEnd.value\"\n          :as-sprite=\"asSprite.value\"\n          :center=\"[centerX.value, centerY.value]\"\n          :reversed=\"reversed.value\"\n          :scale=\"scale.value\"\n          :paused=\"paused.value\"\n          :position=\"[position.value[0], position.value[1], position.value[2]]\"\n          :rotation=\"[degToRad(rotationX.value), degToRad(rotationY.value), degToRad(rotationZ.value)]\"\n        />\n      </Suspense>\n    </TresGroup>\n    <TresGroup :position=\"[0, 0, 0]\">\n      <Suspense>\n        <AnimatedSprite\n          :image=\"`${ASSETS_URL}cientosTexture.png`\"\n          :atlas=\"`${ASSETS_URL}cientosAtlas.json`\"\n          :definitions=\"defsParsed\"\n          :flip-x=\"flipX.value\"\n          :as-sprite=\"asSprite.value\"\n          :center=\"[centerX.value, centerY.value]\"\n          :animation=\"animation.value\"\n          :fps=\"fps.value\"\n          :loop=\"loop.value\"\n          :reversed=\"reversed.value\"\n          :reset-on-end=\"resetOnEnd.value\"\n          :scale=\"scale.value\"\n          :paused=\"paused.value\"\n          :position=\"[position.value[0], position.value[1], position.value[2]]\"\n          :rotation=\"[degToRad(rotationX.value), degToRad(rotationY.value), degToRad(rotationZ.value)]\"\n          :depth-write=\"false\"\n          :depth-test=\"false\"\n          @end=\"(frameName) => lastEnd = frameName\"\n          @frame=\"(frameName) => lastFrame = frameName\"\n          @loop=\"(frameName) => lastLoop = frameName\"\n        />\n      </Suspense>\n    </TresGroup>\n    <TresGridHelper :args=\"[10, 10]\" />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/abstractions/BillboardDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { Billboard, Box, OrbitControls } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { Vector3 } from 'three'\nimport '@tresjs/leches/styles'\n\nconst COUNT = 5 * 5\nconst positions = Array.from({ length: COUNT }).fill(0).map((_, i) => {\n  return new Vector3(\n    i % 5 - 2,\n    Math.floor(i / 5) - 2,\n    0,\n  )\n})\n</script>\n\n<template>\n  <TresCanvas clear-color=\"#333333\">\n    <OrbitControls />\n    <TresPerspectiveCamera :position=\"[0, 0, 10]\" />\n    <Billboard v-for=\"position, i of positions\" :key=\"i\" :position=\"position\">\n      <Box :scale=\"[0.5, 0.5, 0.001]\">\n        <TresMeshNormalMaterial />\n      </Box>\n    </Billboard>\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/abstractions/CubeCameraDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { CubeCamera, OrbitControls } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { Fog } from 'three'\n\nconst visible = shallowRef(true)\nconst y0 = shallowRef(1)\nconst y1 = shallowRef(1)\nconst y2 = shallowRef(1)\nconst f = shallowRef(1)\nconst redFog = new Fog('red', 1, 20)\nconst whiteFog = new Fog('white', 1, 20)\nconst fog = shallowRef(whiteFog)\nconst far = shallowRef(1000)\nlet intervalId: ReturnType<typeof setInterval>\n\nlet elapsed = 0\nonMounted(() => {\n  intervalId = setInterval(() => {\n    elapsed += 1000 / 30\n    y0.value = (1 + Math.sin(elapsed * 0.001)) * 6\n    y1.value = (1 + Math.sin(elapsed * 0.001 + 2 * Math.PI / 3)) * 6\n    y2.value = (1 + Math.sin(elapsed * 0.001 + 4 * Math.PI / 3)) * 6\n    visible.value = Math.sin(elapsed * 0.001) > 0\n    f.value = Infinity\n    fog.value = Math.sin(elapsed * 0.1) <= 0 ? redFog : whiteFog\n    // far.value = (Math.sin(elapsed * 0.001) + 1) * 100\n  }, 1000 / 30)\n})\n\nonUnmounted(() => { clearInterval(intervalId) })\n</script>\n\n<template>\n  <TresCanvas clear-color=\"#222\">\n    <TresPerspectiveCamera :position=\"[3, 10, 40]\" />\n    <OrbitControls />\n\n    <TresFog attach=\"fog\" :args=\"['#f0f0f0', 100, 200]\" />\n\n    <CubeCamera :position-y=\"10\" :frames=\"f\" :fog=\"fog\" :far=\"far\">\n      <TresMesh :position-x=\"-8\" :scale=\"2\" :position-y=\"y0\">\n        <TresTorusKnotGeometry />\n        <TresMeshPhysicalMaterial :roughness=\"0.25\" :metalness=\"1\" />\n      </TresMesh>\n\n      <TresMesh :position-x=\"8\" :position-y=\"y1\" :scale=\"5\">\n        <TresSphereGeometry />\n        <TresMeshPhysicalMaterial :roughness=\"0.25\" :metalness=\"1\" />\n      </TresMesh>\n\n      <TresMesh v-if=\"y0 >= 4\" :position-z=\"8\" :position-y=\"y2\" :scale=\"3\">\n        <TresTorusGeometry />\n        <TresMeshPhysicalMaterial :roughness=\"0.25\" :metalness=\"1\" />\n      </TresMesh>\n    </CubeCamera>\n\n    <TresGroup>\n      <TresMesh :position-y=\"2.5\" :position-x=\"y0\">\n        <TresBoxGeometry :args=\"[5, 5, 5]\" />\n        <TresMeshStandardMaterial color=\"hotpink\" />\n      </TresMesh>\n\n      <TresAmbientLight :intensity=\"3.14\" />\n      <TresPointLight :intensity=\"500\" :position=\"[40, 40, 0]\" />\n\n      <TresGridHelper :args=\"[100, 10]\" />\n    </TresGroup>\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/abstractions/EdgesDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { TresCanvas } from '@tresjs/core'\nimport { Box, Edges, OrbitControls } from '@tresjs/cientos'\nimport { TresLeches, useControls } from '@tresjs/leches'\nimport '@tresjs/leches/styles'\n\nconst gl = {\n  powerPreference: 'high-performance',\n  precision: 'highp',\n  clearColor: '#F6B03B',\n}\n\nconst { enabled, edgeColor, edgeThreshold } = useControls({\n  enabled: { value: true, type: 'boolean', label: 'Enabled' },\n  edgeColor: { value: '#292929', type: 'color', label: 'Color' },\n  edgeThreshold: {\n    label: 'Threshold Angle',\n    value: 15,\n    min: 1,\n    max: 100,\n    step: 1,\n  },\n})\n</script>\n\n<template>\n  <TresLeches />\n\n  <TresCanvas\n    v-bind=\"gl\"\n  >\n    <TresPerspectiveCamera\n      :position=\"[0, 2, 5]\"\n    />\n\n    <OrbitControls\n      make-default\n    />\n\n    <TresGridHelper\n      :args=\"[10, 10]\"\n      :position-y=\"-.5\"\n    />\n\n    <Box :position=\"[-1, 0, 0]\">\n      <TresMeshBasicMaterial color=\"#f6f6f6\" />\n\n      <Edges\n        v-if=\"enabled.value\"\n        :scale=\"1.1\"\n        :threshold=\"edgeThreshold.value\"\n      >\n        <TresMeshBasicMaterial\n          :color=\"edgeColor.value\"\n        />\n      </Edges>\n    </Box>\n\n    <Box :position=\"[1, 0, 0]\">\n      <TresMeshBasicMaterial color=\"#292929\" />\n\n      <Edges\n        :scale=\"1.1\"\n        :threshold=\"edgeThreshold.value\"\n        color=\"#f6f6f6\"\n      />\n    </Box>\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/abstractions/GlobalAudioDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { GlobalAudio } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { shallowRef, watch } from 'vue'\n\nconst exampleAudio\n  = 'https://raw.githubusercontent.com/Tresjs/assets/main/music/sunny-afternoon.mp3'\n\nconst isPlaying = shallowRef(false)\nconst soundRef = shallowRef()\n\nwatch(soundRef, (value) => {\n  // eslint-disable-next-line no-console\n  console.log(value.instance)\n})\n</script>\n\n<template>\n  <div class=\"floating-controls\">\n    <button id=\"playBtn\">\n      {{ !isPlaying ? 'Play' : 'Pause' }}\n    </button>\n    <button id=\"stopBtn\">\n      Stop\n    </button>\n  </div>\n  <TresCanvas clear-color=\"#82DBC5\">\n    <TresPerspectiveCamera\n      :position=\"[0, 0, 7.5]\"\n      :fov=\"75\"\n      :near=\"0.1\"\n      :far=\"1000\"\n    />\n    <Suspense>\n      <GlobalAudio\n        ref=\"soundRef\"\n        :src=\"exampleAudio\"\n        :volume=\"0.5\"\n        :loop=\"true\"\n        :playback-rate=\"1\"\n        play-trigger=\"playBtn\"\n        stop-trigger=\"stopBtn\"\n        @is-playing=\"(e) => isPlaying = e\"\n      />\n    </Suspense>\n  </TresCanvas>\n</template>\n\n<style scoped>\n.floating-controls {\n  position: absolute;\n  top: 0;\n  left: 0;\n  z-index: 100;\n  padding: 1rem;\n  display: flex;\n  flex-direction: column;\n  gap: 1rem;\n  background: rgba(0, 0, 0, 0.5);\n  color: white;\n}\n</style>\n"
  },
  {
    "path": "playground/vue/src/pages/abstractions/GradientTextureDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { GradientTexture, OrbitControls } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { Color } from 'three'\n\nconst gl = {\n  clearColor: '#82DBC5',\n}\n\nconst CIENTOS = {\n  BLUE: '#82dbc5',\n  GREY: '#4f4f4f',\n  ORANGE: '#fbb03b',\n}\nconst GRADIENTS = [\n  { stops: [0.0, 0.1, 0.8], colors: [CIENTOS.GREY, CIENTOS.BLUE, CIENTOS.ORANGE] },\n  { stops: [0.0], colors: [CIENTOS.GREY] },\n  { stops: [0.5, 1.0], colors: [CIENTOS.BLUE, CIENTOS.GREY] },\n  { stops: [0.0, 0.1, 0.8], colors: [CIENTOS.BLUE, CIENTOS.ORANGE, CIENTOS.ORANGE] },\n]\n\nconst i = shallowRef(0)\nconst stops = ref([0, 0.25, 1.0])\nconst colors = ref([new Color('red'), new Color('blue'), new Color('green')])\n\nlet intervalId: ReturnType<typeof setInterval>\nlet elapsed = 0\n\nonMounted(() => {\n  intervalId = setInterval(() => {\n    elapsed += 0.1\n    i.value = Math.floor(elapsed) % GRADIENTS.length\n\n    stops.value[0] = Math.abs(Math.sin(elapsed))\n    stops.value[1] = Math.abs(Math.sin(elapsed + 0.5))\n    stops.value[2] = Math.abs(Math.sin(elapsed + 1))\n  }, 1000 / 30)\n})\n\nonUnmounted(() => { clearInterval(intervalId) })\n</script>\n\n<template>\n  <TresCanvas v-bind=\"gl\">\n    <TresPerspectiveCamera :position=\"[0, 0, 3]\" />\n    <OrbitControls />\n\n    <TresMesh :position-x=\"0.75\">\n      <TresPlaneGeometry />\n      <TresMeshBasicMaterial>\n        <GradientTexture :stops=\"GRADIENTS[i].stops\" :colors=\"GRADIENTS[i].colors\" />\n      </TresMeshBasicMaterial>\n    </TresMesh>\n\n    <TresMesh :position-x=\"-0.75\">\n      <TresPlaneGeometry />\n      <TresMeshBasicMaterial>\n        <GradientTexture type=\"radial\" :stops=\"stops\" :colors=\"colors\" :width=\"1024\" />\n      </TresMeshBasicMaterial>\n    </TresMesh>\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/abstractions/ImageDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { TresCanvas } from '@tresjs/core'\nimport { Image, OrbitControls } from '@tresjs/cientos'\nimport { Color, DoubleSide, FrontSide, NoToneMapping } from 'three'\nimport { TresLeches, useControls } from '@tresjs/leches'\nimport '@tresjs/leches/styles'\n\nconst URLS = [\n  'https://upload.wikimedia.org/wikipedia/commons/1/13/20220713-great-tit.jpg',\n  'https://upload.wikimedia.org/wikipedia/commons/0/00/Friendly_Robin.jpg',\n]\n\nconst c = useControls({\n  url: 'https://upload.wikimedia.org/wikipedia/commons/d/d4/Mars_2009_Plouaret.jpg',\n  segments: { value: 1, min: 1, max: 10, step: 1 },\n  scaleX: { value: 1, min: 0, max: 3, step: 0.01 },\n  scaleY: { value: 1, min: 0, max: 3, step: 0.01 },\n  isRed: false,\n  zoom: { value: 1, min: 0, max: 3, step: 0.01 },\n  radius: { value: 0, min: 0, max: 1, step: 0.01 },\n  grayscale: { value: 0, min: 0, max: 1, step: 0.01 },\n  toneMapped: false,\n  transparent: true,\n  opacity: { value: 1, min: 0, max: 1, step: 0.01 },\n  isDoubleSided: true,\n  enabled: true,\n})\n\nconst opacity = shallowRef(1)\nconst url = shallowRef(URLS[0])\nconst sx = shallowRef(1)\n\nlet elapsed = 0\nsetInterval(() => {\n  elapsed += 0.01\n  opacity.value = Math.abs(Math.sin(elapsed))\n  url.value = Math.sin(elapsed) > 0 ? URLS[0] : URLS[1]\n  sx.value = (Math.cos(elapsed) * 0.5 + 0.5)\n}, 1000 / 30)\n</script>\n\n<template>\n  <TresLeches />\n  <TresCanvas :tone-mapping=\"NoToneMapping\">\n    <TresPerspectiveCamera />\n    <OrbitControls />\n    <Image\n      :position-y=\"2\"\n      :url=\"url\"\n      :radius=\"opacity\"\n      :color=\"new Color('white')\"\n    >\n      <TresBoxGeometry />\n    </Image>\n    <Image\n      v-if=\"c.enabled.value.value\"\n      :url=\"c.url.value.value\"\n      :segments=\"c.segments.value.value\"\n      :scale=\"[c.scaleX.value.value, c.scaleY.value.value]\"\n      :color=\"c.isRed.value.value ? '#F00' : '#FFF'\"\n      :zoom=\"c.zoom.value.value\"\n      :radius=\"c.radius.value.value\"\n      :grayscale=\"c.grayscale.value.value\"\n      :tone-mapped=\"c.toneMapped.value.value\"\n      :transparent=\"c.transparent.value.value\"\n      :opacity=\"c.opacity.value.value\"\n      :side=\"c.isDoubleSided.value.value ? DoubleSide : FrontSide\"\n    />\n    <Image\n      :position-x=\"2\"\n      :scale=\"[sx, 1]\"\n      :url=\"url\"\n    />\n    <Image\n      :position-y=\"-2\"\n      :scale=\"sx\"\n      :url=\"url\"\n    >\n      <TresCircleGeometry />\n    </Image>\n\n    <Image\n      :position-x=\"-2\"\n      :url=\"url\"\n      :radius=\"opacity\"\n      :transparent=\"true\"\n    />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/abstractions/LensflareDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { Lensflare, OrbitControls, Torus } from '@tresjs/cientos'\nimport { TresCanvas, useRenderLoop } from '@tresjs/core'\nimport { TresLeches, useControls } from '@tresjs/leches'\nimport { shallowRef } from 'vue'\nimport '@tresjs/leches/styles'\n\nconst [x, z] = [shallowRef(0), shallowRef(0)]\nuseRenderLoop().onLoop(({ elapsed }) => {\n  z.value = Math.cos(elapsed * 0.5) * 2\n  x.value = Math.sin(elapsed)\n})\n\nconst { value: scale } = useControls({\n  scale: { value: 0.33, min: 0.01, max: 2, step: 0.01 },\n})\n</script>\n\n<template>\n  <TresLeches class=\"important-top-4 important-left-4\" />\n  <TresCanvas clear-color=\"#333\">\n    <TresPerspectiveCamera />\n    <OrbitControls />\n    <TresPointLight :position=\"[x, 0, z]\">\n      <Lensflare\n        :seed=\"1028\"\n        :scale=\"scale\"\n      />\n    </TresPointLight>\n    <Torus\n      v-for=\"n in [-2, 0, 2]\"\n      :key=\"n\"\n      :args=\"[0.7, 0.15]\"\n      :position-z=\"n\"\n      :rotation-y=\"Math.PI * 0.5\"\n    >\n      <TresMeshPhongMaterial color=\"#888\" />\n    </Torus>\n    <TresGridHelper :position=\"[0, -0.9, 0]\" />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/abstractions/LeviosoDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { Levioso, OrbitControls, TorusKnot } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { TresLeches, useControls } from '@tresjs/leches'\nimport { BasicShadowMap, NoToneMapping, SRGBColorSpace } from 'three'\nimport { shallowReactive, shallowRef } from 'vue'\nimport '@tresjs/leches/styles'\n\nconst gl = {\n  clearColor: '#82DBC5',\n  shadows: true,\n  alpha: false,\n  shadowMapType: BasicShadowMap,\n  outputColorSpace: SRGBColorSpace,\n  toneMapping: NoToneMapping,\n}\n\nconst leviosoState = shallowReactive({\n  speed: 5,\n  rotationFactor: 1,\n  floatFactor: 1,\n  range: [-0.1, 0.1],\n})\n\nconst { speed, rotationFactor, floatFactor } = useControls({\n  speed: { value: leviosoState.speed, min: 0, max: 100, step: 1 },\n  rotationFactor: { value: leviosoState.rotationFactor, min: 0, max: 10, step: 1 },\n  floatFactor: { value: leviosoState.floatFactor, min: 0, max: 10, step: 1 },\n})\n\nwatch([speed.value, rotationFactor.value, floatFactor.value], () => {\n  leviosoState.speed = speed.value.value\n  leviosoState.rotationFactor = rotationFactor.value.value\n  leviosoState.floatFactor = floatFactor.value.value\n})\nconst groupRef = shallowRef()\n</script>\n\n<template>\n  <TresLeches />\n  <TresCanvas v-bind=\"gl\">\n    <TresPerspectiveCamera :position=\"[11, 11, 11]\" />\n    <OrbitControls />\n    <Levioso\n      ref=\"groupRef\"\n      v-bind=\"leviosoState\"\n    >\n      <TorusKnot :position=\"[0, 4, 0]\">\n        <TresMeshNormalMaterial />\n      </TorusKnot>\n    </Levioso>\n    <TresGridHelper :args=\"[10, 10]\" />\n    <TresAmbientLight :intensity=\"1\" />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/abstractions/MarchingCubesDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { MarchingCube, MarchingCubes, MarchingPlane, OrbitControls } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { NoToneMapping } from 'three'\nimport { TresLeches, useControls } from '@tresjs/leches'\nimport '@tresjs/leches/styles'\n\nconst r0 = shallowRef()\nconst r1 = shallowRef()\nconst r2 = shallowRef()\nconst r3 = shallowRef()\nconst r4 = shallowRef()\nconst r5 = shallowRef()\nconst r6 = shallowRef()\nconst r7 = shallowRef()\nconst r8 = shallowRef()\nconst r9 = shallowRef()\n\nlet time = 0\nsetInterval(() => {\n  time += 1 / 30\n  let i = 0\n  for (const r of [r0, r1, r2, r3, r4, r5, r6, r7, r8, r9]) {\n    if (!r.value) { return }\n    const p = r.value.instance.position\n    p.x = Math.sin(i + 1.26 * time * (1.03 + 0.5 * Math.cos(0.21 * i))) * 0.27\n    p.y = Math.cos(i + 1.12 * time * Math.cos(1.22 + 0.1424 * i)) * 0.77\n    p.z = Math.cos(i + 1.32 * time * 0.1 * Math.sin((0.92 + 0.53 * i))) * 0.27\n    i++\n  }\n}, 1000 / 30)\n\nconst c = useControls({\n  hasWallX: true,\n  hasWallY: true,\n  hasWallZ: true,\n  x: { value: 0, min: -1, max: 1, step: 0.1 },\n  y: { value: 0, min: -1, max: 1, step: 0.1 },\n  z: { value: 0, min: -1, max: 1, step: 0.1 },\n  strength: { value: 0.5, min: -5, max: 5 },\n  subtract: { value: 12, min: 0, max: 100 },\n  enableColors: true,\n})\n</script>\n\n<template>\n  <TresLeches />\n  <TresCanvas clear-color=\"#82DBC5\" :tone-mapping=\"NoToneMapping\">\n    <TresPerspectiveCamera :position=\"[0, 0.5, 5]\" />\n    <OrbitControls />\n    <TresGridHelper :args=\"[10, 10]\" />\n    <MarchingCubes :enable-colors=\"true\" :resolution=\"40\" :max-poly-count=\"40000\">\n      <MarchingPlane v-if=\"c.hasWallX.value.value\" plane-type=\"x\" />\n      <MarchingPlane v-if=\"c.hasWallY.value.value\" plane-type=\"y\" />\n      <MarchingPlane v-if=\"c.hasWallZ.value.value\" plane-type=\"z\" />\n\n      <MarchingCube\n        :position=\"[c.x.value.value, c.y.value.value, c.z.value.value]\"\n        :strength=\"c.strength.value.value\"\n        :subtract=\"c.subtract.value.value\"\n      />\n      <MarchingCube ref=\"r0\" color=\"red\" />\n      <MarchingCube ref=\"r1\" color=\"red\" />\n      <MarchingCube ref=\"r2\" color=\"red\" />\n      <MarchingCube ref=\"r3\" color=\"blue\" />\n      <MarchingCube ref=\"r4\" color=\"blue\" />\n      <MarchingCube ref=\"r5\" color=\"blue\" />\n      <MarchingCube ref=\"r6\" color=\"green\" />\n      <MarchingCube ref=\"r7\" color=\"green\" />\n      <MarchingCube ref=\"r8\" color=\"green\" />\n      <MarchingCube ref=\"r9\" color=\"green\" />\n\n      <TresMeshBasicMaterial v-if=\"c.enableColors.value.value\" :vertex-colors=\"true\" />\n      <TresMeshPhongMaterial v-else specular=\"#111111\" :shininess=\"30\" color=\"#049ef4\" :reflectivity=\"1\" />\n    </MarchingCubes>\n    <TresAxesHelper />\n\n    <TresDirectionalLight color=\"#ffffff\" :intensity=\"3\" :position=\"[0, 200, 0]\" />\n    <TresDirectionalLight color=\"#ffffff\" :intensity=\"3\" :position=\"[100, 200, 100]\" />\n\n    <OrbitControls :enable-pan=\"false\" :zoom-speed=\"0.5\" />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/abstractions/MaskDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { NoToneMapping } from 'three'\nimport { Mask, OrbitControls, useMask } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { TresLeches, useControls } from '@tresjs/leches'\nimport '@tresjs/leches/styles'\n\nconst c = useControls({\n  id: { value: 1, min: 1, max: 2, step: 1 },\n  invert: false,\n  colorWrite: false,\n  depthWrite: false,\n  enabled: true,\n})\n\n// NOTE: Leches doesn't return a ref, which is what we\n// want to test here. Create duplicate refs.\nconst id = shallowRef(1)\nconst invert = shallowRef(false)\nconst m = useMask(id, invert)\n\nwatch(c.id.value, () => id.value = c.id.value.value)\nwatch(c.invert.value, () => invert.value = c.invert.value.value)\n</script>\n\n<template>\n  <TresLeches />\n  <TresCanvas :tone-mapping=\"NoToneMapping\" :stencil=\"true\" clear-color=\"white\">\n    <TresPerspectiveCamera :position=\"[11, 11, 11]\" />\n    <OrbitControls />\n\n    <TresGroup :position-y=\"1\">\n      <TresMesh>\n        <TresRingGeometry :args=\"[0.9, 1, 64]\" />\n        <TresMeshPhongMaterial color=\"black\" />\n      </TresMesh>\n      <Mask v-if=\"c.enabled.value.value\" :id=\"2\" :depth-write=\"c.depthWrite.value.value\" :color-write=\"c.colorWrite.value.value\">\n        <TresCircleGeometry />\n        <TresMeshBasicMaterial color=\"red\" />\n      </Mask>\n    </TresGroup>\n\n    <TresGroup :position-y=\"-1\">\n      <TresMesh>\n        <TresRingGeometry :args=\"[0.9, 1, 64]\" />\n        <TresMeshPhongMaterial color=\"black\" />\n      </TresMesh>\n      <Mask v-if=\"c.enabled.value.value\" :id=\"1\" :depth-write=\"c.depthWrite.value.value\" :color-write=\"c.colorWrite.value.value\">\n        <TresCircleGeometry />\n        <TresMeshBasicMaterial color=\"blue\" />\n      </Mask>\n    </TresGroup>\n\n    <TresMesh :scale=\"1.5\">\n      <TresBoxGeometry />\n      <TresMeshNormalMaterial v-bind=\"m\" />\n    </TresMesh>\n\n    <TresMesh :position=\"[0, 0, -3]\">\n      <TresBoxGeometry />\n      <TresMeshNormalMaterial />\n    </TresMesh>\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/abstractions/MouseParallaxDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { MouseParallax, TorusKnot } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { BasicShadowMap, NoToneMapping, SRGBColorSpace } from 'three'\n\nconst gl = {\n  clearColor: '#82DBC5',\n  shadows: true,\n  alpha: false,\n  shadowMapType: BasicShadowMap,\n  outputColorSpace: SRGBColorSpace,\n  toneMapping: NoToneMapping,\n}\n</script>\n\n<template>\n  <TresCanvas v-bind=\"gl\">\n    <TresPerspectiveCamera\n      :position=\"[0, 0, 7.5]\"\n    />\n    <TorusKnot>\n      <TresMeshNormalMaterial />\n    </TorusKnot>\n    <MouseParallax :factor=\"[3, 15]\" :ease=\"[3, 0.5]\" />\n    <TresAmbientLight :intensity=\"1\" />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/abstractions/OutlineDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { TresCanvas } from '@tresjs/core'\nimport { OrbitControls, Outline } from '@tresjs/cientos'\n\nconst thickness = shallowRef(1)\nconst color = shallowRef('black')\nlet elapsed = 0\nlet intervalId: ReturnType<typeof setInterval>\nonMounted(() => {\n  intervalId = setInterval(() => {\n    elapsed += 0.01 * 1000 / 30\n    thickness.value = (1 + Math.sin(elapsed)) * 5\n\n    color.value = Math.cos(elapsed) > 0 ? 'blue' : 'orange'\n  }, 1000 / 30)\n})\n\nonUnmounted(() => clearInterval(intervalId))\n</script>\n\n<template>\n  <TresCanvas>\n    <TresPerspectiveCamera :position=\"[0, 0, 10]\" />\n    <OrbitControls />\n    <TresMesh>\n      <TresTorusKnotGeometry />\n      <TresMeshBasicMaterial />\n      <Outline :thickness=\"thickness\" :color=\"color\" />\n    </TresMesh>\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/abstractions/PositionalAudioDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { Box, OrbitControls, PositionalAudio } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { useState } from '../../composables/state'\n\nconst gl = {\n  clearColor: '#82DBC5',\n  shadows: true,\n  alpha: false,\n}\n\nconst ready = ref(false)\nconst positionalAudioIsPlaying = ref(false)\nconst positionalAudioRef = shallowRef(null)\n\nconst handlerAudio = (action: string) => {\n  if (!positionalAudioRef.value) { return }\n\n  const { play, pause, stop } = positionalAudioRef.value\n\n  if (action === 'play') {\n    play()\n  }\n  else if (action === 'pause') {\n    pause()\n  }\n  else if (action === 'stop') {\n    stop()\n  }\n}\n\nconst onContinue = () => {\n  ready.value = true\n}\n\nconst { renderingTimes } = useState()\n\nfunction onRender() {\n  renderingTimes.value = 1\n}\n</script>\n\n<template>\n  <div\n    v-if=\"!ready\"\n    class=\"playground-positional-audio__ready\"\n  >\n    <button @click=\"onContinue\">\n      click to continue\n    </button>\n  </div>\n\n  <div\n    v-if=\"ready\"\n    class=\"playground-positional-audio__controls\"\n  >\n    <div class=\"playground-positional-audio__controls-events\">\n      <p>\n        @is-playing: {{ positionalAudioIsPlaying }}\n      </p>\n    </div>\n\n    <div class=\"playground-positional-audio__controls-methods\">\n      <button @click=\"handlerAudio('play')\">\n        play\n      </button>\n      <button @click=\"handlerAudio('pause')\">\n        pause\n      </button>\n      <button @click=\"handlerAudio('stop')\">\n        stop\n      </button>\n    </div>\n  </div>\n  <GraphPane />\n  <TresCanvas v-bind=\"gl\" render-mode=\"on-demand\" @render=\"onRender\">\n    <TresPerspectiveCamera :position=\"[0, 0.5, 5]\" />\n    <OrbitControls />\n\n    <Box :args=\"[1, 1, 1]\">\n      <TresMeshNormalMaterial />\n\n      <Suspense>\n        <PositionalAudio\n          ref=\"positionalAudioRef\"\n          :ready=\"ready\"\n          :inner-angle=\"180\"\n          :outer-angle=\"220\"\n          :outer-gain=\".2\"\n          :distance=\"2\"\n          helper\n          url=\"https://raw.githubusercontent.com/Tresjs/assets/main/music/beat-1.mp3\"\n          @is-playing=\"(e) => positionalAudioIsPlaying = e\"\n        />\n      </Suspense>\n    </Box>\n\n    <Box\n      :args=\"[4, 2, 0.1]\"\n      :position=\"[0, 0, -1]\"\n    >\n      <TresMeshBasicMaterial\n        color=\"#ff0000\"\n        transparent\n        :opacity=\"0.5\"\n      />\n    </Box>\n\n    <TresGridHelper\n      :position=\"[0, -.01, 0]\"\n      :args=\"[10, 10]\"\n    />\n  </TresCanvas>\n</template>\n\n<style scoped>\n.playground-positional-audio__ready {\n  width: 100%;\n  height: 100%;\n  position: fixed;\n  z-index: 1;\n  background-color: rgba(0, 0, 0, 0.75);\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  backdrop-filter: blur(5px);\n}\n\n.playground-positional-audio__controls {\n  position: fixed;\n  z-index: 1;\n  display: flex;\n  flex-direction: column;\n  justify-content: center;\n  backdrop-filter: blur(5px);\n  top: 25px;\n  left: 25px;\n  column-gap: 5px;\n}\n\n.playground-positional-audio__controls-methods,\n.playground-positional-audio__controls-events {\n  display: flex;\n  align-items: center;\n  backdrop-filter: blur(5px);\n  top: 25px;\n  left: 25px;\n  column-gap: 5px;\n}\n\n.playground-positional-audio__controls button {\n  padding: 5px 10px;\n}\n</style>\n"
  },
  {
    "path": "playground/vue/src/pages/abstractions/ReflectorMeshDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport {\n  MeshWobbleMaterial,\n  OrbitControls,\n  Reflector,\n  Stars,\n} from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { BasicShadowMap, NoToneMapping, SRGBColorSpace } from 'three'\nimport { shallowRef, watch } from 'vue'\n\nconst gl = {\n  clearColor: '#111',\n  shadows: false,\n  alpha: false,\n  shadowMapType: BasicShadowMap,\n  outputColorSpace: SRGBColorSpace,\n  toneMapping: NoToneMapping,\n}\n\nconst reflectorRef = shallowRef()\n\nwatch(reflectorRef, (value) => {\n  // eslint-disable-next-line no-console\n  console.log(value)\n})\n\nconst options = {\n  color: '#f7f7f7',\n  clipBias: 0,\n  textureWidth: 1024,\n  textureHeight: 1024,\n}\n</script>\n\n<template>\n  <TresCanvas\n    v-bind=\"gl\"\n  >\n    <TresPerspectiveCamera\n      :position=\"[3, 3, 6]\"\n      :look-at=\"[0, 0, 0]\"\n    />\n    <Stars />\n    <TresMesh>\n      <TresTorusGeometry />\n      <MeshWobbleMaterial\n        color=\"orange\"\n        :speed=\"1\"\n        :factor=\"2\"\n      />\n    </TresMesh>\n    <Reflector\n      ref=\"reflectorRef\"\n      :rotation=\"[-Math.PI * 0.5, 0, 0]\"\n      :position=\"[0, -2, 0]\"\n      :color=\"options.color\"\n      :clip-bias=\"options.clipBias\"\n      :texture-width=\"options.textureWidth\"\n      :texture-height=\"options.textureHeight\"\n    />\n    <TresAmbientLight :intensity=\"1\" />\n    <OrbitControls />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/abstractions/Sampler.vue",
    "content": "<script setup lang=\"ts\">\nimport { OrbitControls, Sampler } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { TresLeches, useControls } from '@tresjs/leches'\nimport { ACESFilmicToneMapping, SRGBColorSpace } from 'three'\nimport { ref } from 'vue'\nimport type { Mesh } from 'three'\nimport '@tresjs/leches/styles'\n\nconst gl = {\n  clearColor: '#82DBC5',\n  shadows: true,\n  alpha: false,\n  outputColorSpace: SRGBColorSpace,\n  toneMapping: ACESFilmicToneMapping,\n}\n\nconst torusRef = ref<Mesh>()\nconst instancesRef = ref<Mesh>()\n\nconst { samples } = useControls({\n  samples: {\n    min: 1,\n    max: 50,\n    step: 1,\n    value: 1,\n  },\n})\n</script>\n\n<template>\n  <TresLeches />\n  <TresCanvas v-bind=\"gl\" render-mode=\"on-demand\">\n    <TresPerspectiveCamera :position=\"[0, 0.5, 5]\" />\n    <OrbitControls />\n\n    <Sampler :count=\"samples\">\n      <TresMesh ref=\"torusRef\">\n        <TresTorusGeometry />\n      </TresMesh>\n\n      <TresInstancedMesh\n        ref=\"instancesRef\"\n        :args=\"[null!, null!, 1000]\"\n      >\n        <TresBoxGeometry\n          :args=\"[0.1, 0.1, 0.1]\"\n        />\n        <TresMeshNormalMaterial />\n      </TresInstancedMesh>\n    </Sampler>\n    <TresGridHelper\n      :args=\"[10, 10]\"\n    />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/abstractions/ScreenSizerDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { TresCanvas } from '@tresjs/core'\nimport { OrbitControls, ScreenSizer } from '@tresjs/cientos'\n</script>\n\n<template>\n  <TresCanvas>\n    <TresPerspectiveCamera :position=\"[11, 11, 11]\" />\n    <OrbitControls />\n    <ScreenSizer>\n      <TresMesh>\n        <TresBoxGeometry :args=\"[100, 100, 100]\" />\n        <TresMeshNormalMaterial />\n      </TresMesh>\n    </ScreenSizer>\n    <TresMesh :position-x=\"2\">\n      <TresBoxGeometry />\n      <TresMeshNormalMaterial />\n    </TresMesh>\n    <TresGridHelper :args=\"[10, 10]\" />\n    <TresAmbientLight :intensity=\"1\" />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/abstractions/ScreenSpaceDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { OrbitControls, ScreenSpace } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\n</script>\n\n<template>\n  <TresCanvas>\n    <TresPerspectiveCamera />\n    <OrbitControls />\n    <ScreenSpace :depth=\"5\">\n      <TresMesh>\n        <TresTorusGeometry />\n        <TresMeshNormalMaterial />\n      </TresMesh>\n    </ScreenSpace>\n    <TresGridHelper :args=\"[10, 10]\" />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/abstractions/Text3DDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { OrbitControls, Text3D } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { BasicShadowMap, NoToneMapping, SRGBColorSpace } from 'three'\nimport { ref } from 'vue'\n\nconst gl = {\n  clearColor: '#82DBC5',\n  shadows: true,\n  alpha: false,\n  shadowMapType: BasicShadowMap,\n  outputColorSpace: SRGBColorSpace,\n  toneMapping: NoToneMapping,\n}\n\nconst fontPath = 'https://raw.githubusercontent.com/Tresjs/assets/main/fonts/FiraCodeRegular.json'\n\nconst reactiveText = ref('You can edit me')\n</script>\n\n<template>\n  <div class=\"input-center\">\n    <input v-model=\"reactiveText\" />\n  </div>\n  <TresCanvas v-bind=\"gl\">\n    <TresPerspectiveCamera :position=\"[0, 0.5, 5]\" />\n    <OrbitControls />\n    <Suspense>\n      <Text3D\n        :text=\"reactiveText\"\n        :size=\"0.3\"\n        :font=\"fontPath\"\n        center\n        :need-updates=\"true\"\n      />\n    </Suspense>\n    <TresGridHelper :args=\"[10, 10]\" />\n    <TresAmbientLight :intensity=\"1\" />\n  </TresCanvas>\n</template>\n\n<style scoped>\n.input-center {\n  display: flex;\n  justify-content: center;\n  padding: 0.25rem;\n}\n</style>\n"
  },
  {
    "path": "playground/vue/src/pages/abstractions/fbo/FBODemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { Fbo, OrbitControls, Stats } from '@tresjs/cientos'\nimport { useLoop } from '@tresjs/core'\nimport { useControls } from '@tresjs/leches'\n\nconst fboRef = ref(null)\nconst materialRef = ref(null)\nconst torusRef = shallowRef(null)\nconst capsuleRef = shallowRef(null)\n\nconst { onBeforeRender, resume } = useLoop()\n\nconst state = shallowReactive({\n  autoRender: true,\n  depth: false,\n  settings: {\n    samples: 1,\n  },\n})\n\nonMounted(async () => {\n  await nextTick()\n\n  onBeforeRender(({ elapsed /* invalidate */ }) => {\n    torusRef.value.rotation.x = elapsed * 0.745\n    torusRef.value.rotation.y = elapsed * 0.361\n\n    capsuleRef.value.rotation.x = elapsed * 0.471\n    capsuleRef.value.rotation.z = elapsed * 0.632\n\n    /*  invalidate() */\n  })\n  resume()\n})\n\nconst { 'Depth Buffer': isUseDepthBuffer, 'MSAA Samples': numMsaaSamples } = useControls({\n  'Depth Buffer': state.depth,\n  'MSAA Samples': {\n    label: 'MSAA Samples',\n    value: state.settings.samples,\n    min: 0,\n    max: 8,\n    step: 1,\n  },\n})\n\nwatch(\n  isUseDepthBuffer.value,\n  () => { state.depth = isUseDepthBuffer.value.value },\n)\nwatch(\n  numMsaaSamples.value,\n  () => { state.settings.samples = numMsaaSamples.value.value },\n)\n</script>\n\n<template>\n  <TresPerspectiveCamera :position=\"[0, 0.5, 5]\" />\n  <OrbitControls />\n\n  <TresGridHelper :args=\"[10, 10]\" />\n  <Stats />\n  <Fbo\n    ref=\"fboRef\"\n    v-bind=\"state\"\n  />\n\n  <TresMesh>\n    <TresBoxGeometry :args=\"[1, 1, 1]\" />\n    <TresMeshBasicMaterial\n      ref=\"materialRef\"\n      :color=\"0xFF8833\"\n      :map=\"fboRef?.instance.texture ?? null\"\n    />\n  </TresMesh>\n\n  <TresMesh\n    ref=\"torusRef\"\n    :position=\"[3, 0, 0]\"\n  >\n    <TresTorusGeometry :args=\"[1, 0.5, 16, 100]\" />\n    <TresMeshNormalMaterial />\n  </TresMesh>\n\n  <TresMesh\n    ref=\"capsuleRef\"\n    :position=\"[-2, 0, 0]\"\n  >\n    <TresCapsuleGeometry :args=\"[0.4, 1, 4, 8]\" />\n    <TresMeshNormalMaterial />\n  </TresMesh>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/abstractions/fbo/index.vue",
    "content": "<script setup lang=\"ts\">\nimport { TresCanvas } from '@tresjs/core'\nimport { TresLeches, useControls } from '@tresjs/leches'\nimport Experiment from './FBODemo.vue'\nimport '@tresjs/leches/styles'\n\nuseControls('fpsgraph')\n</script>\n\n<template>\n  <TresLeches />\n  <TresCanvas clear-color=\"#c0ffee\">\n    <Experiment />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/abstractions/fbo/useFBODemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { OrbitControls } from '@tresjs/cientos'\nimport { TresCanvas, useRenderLoop } from '@tresjs/core'\nimport { ACESFilmicToneMapping, SRGBColorSpace } from 'three'\n\nconst gl = {\n  clearColor: '#82DBC5',\n  shadows: true,\n  alpha: false,\n  outputColorSpace: SRGBColorSpace,\n  toneMapping: ACESFilmicToneMapping,\n}\n\nconst torusRef = shallowRef(null)\nconst capsuleRef = shallowRef(null)\n\nconst { onLoop } = useRenderLoop()\n\nonMounted(async () => {\n  await nextTick()\n\n  onLoop(({ elapsed }) => {\n    torusRef.value.rotation.x = elapsed * 0.745\n    torusRef.value.rotation.y = elapsed * 0.361\n\n    capsuleRef.value.rotation.x = elapsed * 0.471\n    capsuleRef.value.rotation.z = elapsed * 0.632\n  })\n})\n</script>\n\n<template>\n  <TresCanvas v-bind=\"gl\">\n    <TresPerspectiveCamera :position=\"[0, 0.5, 5]\" />\n    <OrbitControls />\n\n    <TresGridHelper :args=\"[10, 10]\" />\n\n    <FboCube />\n\n    <TresMesh\n      ref=\"torusRef\"\n      :position=\"[3, 0, 0]\"\n    >\n      <TresTorusGeometry :args=\"[1, 0.5, 16, 100]\" />\n      <TresMeshNormalMaterial />\n    </TresMesh>\n\n    <TresMesh\n      ref=\"capsuleRef\"\n      :position=\"[-2, 0, 0]\"\n    >\n      <TresCapsuleGeometry :args=\"[0.4, 1, 4, 8]\" />\n      <TresMeshNormalMaterial />\n    </TresMesh>\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/abstractions/lensflare/LensflareDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { Lensflare, OrbitControls, Torus } from '@tresjs/cientos'\nimport { useLoop } from '@tresjs/core'\nimport { useControls } from '@tresjs/leches'\nimport { shallowRef } from 'vue'\nimport '@tresjs/leches/styles'\n\nconst [x, z] = [shallowRef(0), shallowRef(0)]\nconst { onBeforeRender } = useLoop()\n\nonBeforeRender(({ elapsed }) => {\n  z.value = Math.cos(elapsed * 0.5) * 2\n  x.value = Math.sin(elapsed)\n})\n\nconst { value: scale } = useControls({\n  scale: { value: 0.33, min: 0.01, max: 2, step: 0.01 },\n})\n</script>\n\n<template>\n  <OrbitControls />\n  <TresPointLight :position=\"[x, 0, z]\">\n    <Lensflare\n      :seed=\"1028\"\n      :scale=\"scale\"\n    />\n  </TresPointLight>\n  <Torus\n    v-for=\"n in [-2, 0, 2]\"\n    :key=\"n\"\n    :args=\"[0.7, 0.15]\"\n    :position-z=\"n\"\n    :rotation-y=\"Math.PI * 0.5\"\n  >\n    <TresMeshPhongMaterial color=\"#888\" />\n  </Torus>\n  <TresGridHelper :position=\"[0, -0.9, 0]\" />\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/abstractions/lensflare/index.vue",
    "content": "<script setup lang=\"ts\">\nimport { TresCanvas } from '@tresjs/core'\nimport { TresLeches, useControls } from '@tresjs/leches'\nimport Experiment from './LensflareDemo.vue'\nimport '@tresjs/leches/styles'\n\nuseControls('fpsgraph')\n</script>\n\n<template>\n  <TresLeches class=\"important-top-4 important-left-4\" />\n  <TresCanvas clear-color=\"#333\" render-mode=\"on-demand\">\n    <Experiment />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/abstractions/use-animations/TheModel.vue",
    "content": "<script setup lang=\"ts\">\nimport { useAnimations, useGLTF } from '@tresjs/cientos'\nimport { useLoop } from '@tresjs/core'\n\nconst { state } = useGLTF('https://raw.githubusercontent.com/Tresjs/assets/main/models/gltf/ugly-naked-bunny/ugly-naked-bunny-animated.gltf', { draco: true })\n\nconst animations = computed(() => state.value?.animations || [])\nconst model = computed(() => state?.value?.scene)\nconst { actions, mixer } = useAnimations(animations, model, {\n  manualUpdate: true,\n})\n\nconst { onBeforeRender } = useLoop()\n\nonBeforeRender(({ delta }) => {\n  mixer.value.update(delta)\n})\n\nconst currentAction = ref()\n\nwatch(actions, (newActions) => {\n  currentAction.value = newActions.Greeting\n  currentAction.value.play()\n})\n</script>\n\n<template>\n  <primitive\n    v-if=\"state?.scene\"\n    :object=\"state?.scene\"\n  />\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/abstractions/use-animations/index.vue",
    "content": "<script setup lang=\"ts\">\nimport { OrbitControls } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport TheModel from './TheModel.vue'\n\nconst gl = {\n  clearColor: '#82DBC5',\n  shadows: true,\n}\n</script>\n\n<template>\n  <TresCanvas v-bind=\"gl\">\n    <TresPerspectiveCamera :position=\"[5.3, 2.45, 9.3]\" :look-at=\"[0, 0, 0]\" />\n    <OrbitControls />\n    <TheModel />\n    <TresMesh\n      :rotate-x=\"Math.PI * -0.5\"\n      receive-shadow\n    >\n      <TresPlaneGeometry :args=\"[40, 40]\" />\n      <TresMeshStandardMaterial :color=\"0xF7F7F7\" />\n    </TresMesh>\n    <TresAmbientLight :intensity=\"1\" />\n    <TresDirectionalLight\n      :intensity=\"1\"\n      cast-shadow\n      :position=\"[5, 10, 5]\"\n    />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/abstractions/useSurfaceSampler.vue",
    "content": "<script setup lang=\"ts\">\nimport { OrbitControls, useSurfaceSampler } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\n\nconst torusRef = ref()\nconst instancesRef = ref()\n\nwatch(torusRef, (value) => {\n  useSurfaceSampler(value, 50, instancesRef.value, 'color')\n})\n</script>\n\n<template>\n  <TresCanvas clear-color=\"#82DBC5\">\n    <TresPerspectiveCamera :position=\"[0, 0.5, 5]\" />\n    <OrbitControls />\n\n    <TresMesh\n      ref=\"torusRef\"\n    >\n      <TresTorusGeometry />\n    </TresMesh>\n\n    <TresInstancedMesh\n      ref=\"instancesRef\"\n      :args=\"[null!, null!, 1_000]\"\n    >\n      <TresSphereGeometry\n        :args=\"[0.1, 32, 32]\"\n      />\n      <TresMeshNormalMaterial />\n    </TresInstancedMesh>\n\n    <TresGridHelper\n      :args=\"[10, 10]\"\n    />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/controls/CameraControlsDemo.vue",
    "content": "<!-- eslint-disable no-console -->\n<script setup lang=\"ts\">\nimport { CameraControls } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { TresLeches, useControls } from '@tresjs/leches'\nimport { BasicShadowMap, MathUtils, NoToneMapping, SRGBColorSpace } from 'three'\nimport { reactive, shallowRef } from 'vue'\nimport '@tresjs/leches/styles'\n\nconst gl = {\n  clearColor: '#82DBC5',\n  shadows: true,\n  alpha: false,\n  shadowMapType: BasicShadowMap,\n  outputColorSpace: SRGBColorSpace,\n  toneMapping: NoToneMapping,\n}\n\nconst controlsState = reactive({\n  distance: 5,\n  minDistance: 0,\n  maxDistance: 100,\n})\n\nconst controlsRef = shallowRef()\nconst boxMeshRef = shallowRef()\n\nfunction onChange() {\n  console.log('change')\n}\n\nfunction onStart() {\n  console.log('start')\n}\n\nfunction onEnd() {\n  console.log('end')\n}\n\nconst { distance, minDistance, maxDistance } = useControls({\n  distance: {\n    value: controlsState.distance,\n    min: 0,\n    max: 100,\n    step: 0.01,\n  },\n  minDistance: {\n    value: controlsState.minDistance,\n    min: 0,\n    max: 10,\n    step: 0.01,\n  },\n  maxDistance: {\n    value: controlsState.maxDistance,\n    min: 0,\n    max: 100,\n    step: 0.01,\n  },\n})\n\nwatch([distance.value, minDistance.value, maxDistance.value], () => {\n  controlsState.distance = distance.value.value\n  controlsState.minDistance = minDistance.value.value\n  controlsState.maxDistance = maxDistance.value.value\n})\n\nuseControls(\n  'Dolly',\n  {\n    dollyInc: {\n      type: 'button',\n      onClick: () => {\n        controlsRef?.value?.value?.dolly(1, true)\n      },\n      label: 'Increment (+1)',\n    },\n    dollyDec: {\n      type: 'button',\n      onClick: () => {\n        controlsRef?.value?.value?.dolly(-1, true)\n      },\n      label: 'Increment (-1)',\n    },\n  },\n)\n\nuseControls(\n  'Rotate',\n  {\n    rotateTheta45: {\n      type: 'button',\n      label: 'Rotate theta 45°',\n      onClick: () => {\n        controlsRef?.value?.value?.rotate(45 * MathUtils.DEG2RAD, 0, true)\n      },\n    },\n    rotateTheta90: {\n      type: 'button',\n      label: 'Rotate theta -90°',\n      onClick: () => {\n        controlsRef?.value?.value?.rotate(-90 * MathUtils.DEG2RAD, 0, true)\n      },\n    },\n    rotateTheta360: {\n      type: 'button',\n      label: 'Rotate theta 360°',\n      onClick: () => {\n        controlsRef?.value?.value?.rotate(360 * MathUtils.DEG2RAD, 0, true)\n      },\n    },\n    rotatePhi20: {\n      type: 'button',\n      label: 'Rotate phi 20°',\n      onClick: () => {\n        controlsRef?.value?.value?.rotate(0, 20 * MathUtils.DEG2RAD, true)\n      },\n    },\n  },\n)\n\nuseControls(\n  'Move',\n  {\n    fitToBoundingBox: {\n      type: 'button',\n      label: 'Fit to the bounding box of the mesh',\n      onClick: () => {\n        controlsRef?.value?.value?.fitToBox(boxMeshRef.value, true)\n      },\n    },\n  },\n)\n</script>\n\n<template>\n  <TresLeches />\n  <TresCanvas v-bind=\"gl\">\n    <TresPerspectiveCamera :position=\"[5, 5, 5]\" />\n    <CameraControls\n      v-bind=\"controlsState\"\n      ref=\"controlsRef\"\n      make-default\n      @change=\"onChange\"\n      @start=\"onStart\"\n      @end=\"onEnd\"\n    />\n    <TresGridHelper :position=\"[0, -1, 0]\" />\n    <TresMesh ref=\"boxMeshRef\">\n      <TresBoxGeometry :args=\"[2, 2, 2]\" />\n      <TresMeshBasicMaterial\n        color=\"orange\"\n        wireframe\n      />\n    </TresMesh>\n    <TresAmbientLight :intensity=\"1\" />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/controls/HelperDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { BoxHelper, DirectionalLightHelper } from 'three'\nimport { VertexNormalsHelper } from 'three-stdlib'\nimport { Helper, OrbitControls } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\n\nconst hasHelpers = ref(true)\nconst click = () => {\n  hasHelpers.value = !hasHelpers.value\n}\n\nconst px = shallowRef(0)\nconst py = shallowRef(0)\nlet elapsed = 0\nsetInterval(() => {\n  elapsed += 1000 / 30\n  px.value = Math.cos(elapsed * 0.001) * 10\n  py.value = Math.sin(elapsed * 0.001) * 10\n}, 1000 / 30)\n</script>\n\n<template>\n  <TresCanvas @pointerdown=\"click\">\n    <TresPerspectiveCamera :position=\"[10, 10, 10]\" />\n    <OrbitControls />\n\n    <TresMesh :position=\"[px, 2, 0]\">\n      <TresSphereGeometry />\n      <TresMeshBasicMaterial />\n      <Helper v-if=\"hasHelpers\" :type=\"BoxHelper\" :args=\"['royalblue']\" />\n      <Helper v-if=\"hasHelpers\" :type=\"VertexNormalsHelper\" :args=\"[1, 0xFF0000]\" />\n    </TresMesh>\n\n    <TresDirectionalLight :position=\"[0, py, 2]\">\n      <Helper v-if=\"hasHelpers\" :type=\"DirectionalLightHelper\" />\n    </TresDirectionalLight>\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/controls/KeyboardControlsDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { Box, KeyboardControls } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { BasicShadowMap, NoToneMapping } from 'three'\n\nconst gl = {\n  clearColor: '#82DBC5',\n  shadows: true,\n  alpha: false,\n  shadowMapType: BasicShadowMap,\n  toneMapping: NoToneMapping,\n}\n\nconst isActive = (state: boolean) => {\n  // eslint-disable-next-line no-console\n  console.log(state)\n}\nconst hasChange = (state: any) => {\n  // eslint-disable-next-line no-console\n  console.log('change', state)\n}\n</script>\n\n<template>\n  <TresCanvas v-bind=\"gl\">\n    <TresPerspectiveCamera :position=\"[0, 3, 10]\" />\n    <!-- <Sky /> -->\n    <KeyboardControls\n      @change=\"state => hasChange(state)\"\n      @is-lock=\"state => isActive(state)\"\n    />\n    <Box />\n    <Box :position=\"[15, 0, 0]\" />\n    <Box :position=\"[-15, 0, 0]\" />\n\n    <TresAxesHelper\n      :args=\"[10]\"\n      :position-y=\"5\"\n    />\n    <TresGridHelper :args=\"[100, 100]\" />\n    <TresAmbientLight :intensity=\"1\" />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/controls/MapControlsDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { MapControls, Sphere } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { NoToneMapping, SRGBColorSpace } from 'three'\n\nconst gl = {\n  clearColor: '#82DBC5',\n  alpha: false,\n  outputColorSpace: SRGBColorSpace,\n  toneMapping: NoToneMapping,\n}\n</script>\n\n<template>\n  <TresCanvas v-bind=\"gl\">\n    <TresPerspectiveCamera :position=\"[3, 3, 3]\" />\n    <MapControls />\n    <Sphere :scale=\"0.5\">\n      <TresMeshNormalMaterial />\n    </Sphere>\n    <TresGridHelper :args=\"[10, 10]\" />\n    <TresAmbientLight :intensity=\"1\" />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/controls/OrbitControlsDemo.vue",
    "content": "<!-- eslint-disable no-console -->\n<script setup lang=\"ts\">\nimport { OrbitControls } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { TresLeches, useControls } from '@tresjs/leches'\nimport { BasicShadowMap, MOUSE, NoToneMapping, SRGBColorSpace } from 'three'\nimport { reactive } from 'vue'\nimport { useState } from '../../composables/state'\nimport '@tresjs/leches/styles'\n\nconst gl = {\n  clearColor: '#82DBC5',\n  shadows: true,\n  alpha: false,\n  shadowMapType: BasicShadowMap,\n  outputColorSpace: SRGBColorSpace,\n  toneMapping: NoToneMapping,\n}\n\nconst controlsState = reactive({\n  enableDamping: true,\n  dampingFactor: 0.05,\n  enableZoom: true,\n  autoRotate: false,\n  autoRotateSpeed: 2,\n  maxPolarAngle: Math.PI,\n  minPolarAngle: 0,\n  maxAzimuthAngle: Math.PI,\n  minAzimuthAngle: -Math.PI,\n  enablePan: true,\n  keyPanSpeed: 7,\n  maxDistance: 100,\n  minDistance: 0,\n  minZoom: 0,\n  maxZoom: 100,\n  zoomSpeed: 1,\n  enableRotate: true,\n  rotateSpeed: 1,\n  switchCamera: 'orbit',\n  mouseButtons: {\n    LEFT: MOUSE.ROTATE,\n    MIDDLE: MOUSE.DOLLY,\n    RIGHT: MOUSE.PAN,\n  },\n})\n\nconst {\n  'enable Damping': enableDamping,\n  dampingFactor,\n  'enable Zoom': enableZoom,\n  'enable Pan': enablePan,\n  'enable Rotate': enableRotate,\n  keyPanSpeed,\n  switchCamera,\n} = useControls({\n  'enable Damping': controlsState.enableDamping,\n  'dampingFactor': {\n    value: controlsState.dampingFactor,\n    step: 0.01,\n    min: 0,\n    max: 10,\n  },\n  'enable Zoom': controlsState.enableZoom,\n  'enable Rotate': controlsState.enableRotate,\n  'enable Pan': controlsState.enablePan,\n  'keyPanSpeed': {\n    value: controlsState.keyPanSpeed,\n    step: 0.01,\n    min: 0,\n    max: 10,\n  },\n  'switchCamera': {\n    label: 'Switch Camera',\n    value: controlsState.switchCamera,\n    options: ['orbit', 'firstPerson'],\n  },\n})\n\nwatch([enableDamping.value, dampingFactor.value, enableZoom.value, enablePan.value, keyPanSpeed.value, enableRotate.value], () => {\n  controlsState.enableDamping = enableDamping.value.value\n  controlsState.dampingFactor = dampingFactor.value.value\n  controlsState.enableZoom = enableZoom.value.value\n  controlsState.enablePan = enablePan.value.value\n  controlsState.enableRotate = enableRotate.value.value\n  controlsState.keyPanSpeed = keyPanSpeed.value.value\n})\n\nconst {\n  AnglesMaxPolarAngle,\n  AnglesMinPolarAngle,\n  AnglesMaxAzimuthAngle,\n  AnglesMinAzimuthAngle,\n} = useControls('Angles', {\n  maxPolarAngle: {\n    value: controlsState.maxPolarAngle,\n    step: 0.01,\n    min: 0,\n    max: Math.PI,\n  },\n  minPolarAngle: {\n    value: controlsState.minPolarAngle,\n    step: 0.01,\n    min: 0,\n    max: Math.PI,\n  },\n  maxAzimuthAngle: {\n    value: controlsState.maxAzimuthAngle,\n    step: 0.01,\n    min: 0,\n    max: 2 * Math.PI,\n  },\n  minAzimuthAngle: {\n    value: controlsState.minPolarAngle,\n    step: 0.01,\n    min: 0,\n    max: 2 * Math.PI,\n  },\n})\n\nwatch([\n  AnglesMaxPolarAngle.value,\n  AnglesMinPolarAngle.value,\n  AnglesMaxAzimuthAngle.value,\n  AnglesMinAzimuthAngle.value,\n  keyPanSpeed.value,\n], () => {\n  controlsState.maxPolarAngle = AnglesMaxPolarAngle.value.value\n  controlsState.minPolarAngle = AnglesMinPolarAngle.value.value\n  controlsState.maxAzimuthAngle = AnglesMaxAzimuthAngle.value.value\n  controlsState.minAzimuthAngle = AnglesMinAzimuthAngle.value.value\n})\n\nconst { DistancesMaxDistance, DistancesMinDistance } = useControls('Distances', {\n  maxDistance: {\n    value: controlsState.maxDistance,\n    step: 0.01,\n    min: 0,\n    max: 100,\n  },\n  minDistance: {\n    value: controlsState.minDistance,\n    step: 0.01,\n    min: 0,\n    max: 100,\n  },\n})\n\nwatch([DistancesMaxDistance.value, DistancesMinDistance.value], () => {\n  controlsState.maxDistance = DistancesMaxDistance.value.value\n  controlsState.minDistance = DistancesMinDistance.value.value\n})\n\nconst { ZoomEnableZoom, ZoomMinZoom, ZoomMaxZoom, ZoomZoomSpeed } = useControls('Zoom', {\n  enableZoom: controlsState.enableZoom,\n  minZoom: {\n    value: controlsState.minZoom,\n    step: 0.01,\n    min: 0,\n    max: 10,\n  },\n  maxZoom: {\n    value: controlsState.maxZoom,\n    step: 0.01,\n    min: 0,\n    max: 100,\n  },\n  zoomSpeed: {\n    value: controlsState.zoomSpeed,\n    step: 0.01,\n    min: 0,\n    max: 100,\n  },\n})\n\nwatch([ZoomEnableZoom.value, ZoomMinZoom.value, ZoomMaxZoom.value, ZoomZoomSpeed.value], () => {\n  controlsState.enableZoom = ZoomEnableZoom.value.value\n  controlsState.minZoom = ZoomMinZoom.value.value\n  controlsState.maxZoom = ZoomMaxZoom.value.value\n  controlsState.zoomSpeed = ZoomZoomSpeed.value.value\n})\n\nfunction onChange() {\n  /* console.log('change') */\n}\n\nfunction onStart() {\n  /*  console.log('start') */\n}\n\nfunction onEnd() {\n  /*   console.log('end') */\n}\n\nconst { renderingTimes } = useState()\n\nfunction onRender() {\n  renderingTimes.value = 1\n}\n</script>\n\n<template>\n  <TresLeches />\n  <GraphPane />\n  <TresCanvas v-bind=\"gl\" @render=\"onRender\">\n    <TresPerspectiveCamera v-if=\"switchCamera.value === 'orbit'\" name=\"orbit\" :position=\"[3, 3, 3]\" />\n    <TresPerspectiveCamera v-else name=\"firstPerson\" :position=\"[0, 0, 3]\" />\n    <OrbitControls\n      v-bind=\"controlsState\"\n      @change=\"onChange\"\n      @start=\"onStart\"\n      @end=\"onEnd\"\n    />\n    <TresGridHelper />\n    <TresAmbientLight :intensity=\"1\" />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/controls/PointerLockControlsDemo.vue",
    "content": "<!-- eslint-disable no-console -->\n<script setup lang=\"ts\">\nimport { PointerLockControls, Sky } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { BasicShadowMap, NoToneMapping } from 'three'\n\nconst gl = {\n  clearColor: '#82DBC5',\n  shadows: true,\n  alpha: false,\n  shadowMapType: BasicShadowMap,\n  toneMapping: NoToneMapping,\n}\n\nconst isActive = (state: boolean) => console.log('is-active', state)\nconst hasChange = (state: any) => console.log('change', state)\n</script>\n\n<template>\n  <TresCanvas v-bind=\"gl\">\n    <TresPerspectiveCamera :position=\"[0, 3, 10]\" />\n    <Sky />\n    <PointerLockControls\n      make-default\n      @is-lock=\"state => isActive(state)\"\n      @change=\"state => hasChange(state)\"\n    />\n\n    <TresGridHelper :args=\"[100, 100]\" />\n    <TresAmbientLight :intensity=\"1\" />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/controls/ScrollControlsDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { Box, ScrollControls, Sphere, Stars } from '@tresjs/cientos'\nimport { TresCanvas, useRenderLoop } from '@tresjs/core'\nimport { TresLeches, useControls } from '@tresjs/leches'\nimport { NoToneMapping, SRGBColorSpace } from 'three'\nimport { ref, watchEffect } from 'vue'\nimport '@tresjs/leches/styles'\n\nconst scRef = ref()\nconst sphereRef = ref()\nconst boxRef = ref()\nconst progress = ref(0)\n\nwatchEffect(() => {\n  // eslint-disable-next-line no-console\n  console.log('progress:', progress.value)\n})\n\nconst gl = {\n  clearColor: '#333',\n  alpha: true,\n  outputColorSpace: SRGBColorSpace,\n  toneMapping: NoToneMapping,\n}\n\nuseControls('fpsgraph')\nuseControls({\n  progress: progress.value,\n})\n\nconst { onLoop } = useRenderLoop()\nonLoop(() => {\n  if (boxRef.value) {\n    boxRef.value.instance.rotation.x = progress.value * 10\n    boxRef.value.instance.rotation.y = progress.value * 2\n  }\n})\n</script>\n\n<template>\n  <TresLeches class=\"important-fixed\" />\n  <TresCanvas\n    v-bind=\"gl\"\n    window-size\n  >\n    <TresPerspectiveCamera :position=\"[0, 2, 5]\" />\n    <Stars :radius=\"1\" />\n    <TresGridHelper :args=\"[10, 10]\" />\n\n    <ScrollControls\n      ref=\"scRef\"\n      v-model=\"progress\"\n      :distance=\"10\"\n      :smooth-scroll=\"0.1\"\n      html-scroll\n    >\n      <Sphere\n        ref=\"sphereRef\"\n        :scale=\"0.1\"\n        :position=\"[1, 2, 0]\"\n      />\n      <Box\n        ref=\"boxRef\"\n        :scale=\"0.5\"\n        :color=\"0xFF00FF\"\n        :position=\"[-1, 1, 0]\"\n      />\n    </ScrollControls>\n  </TresCanvas>\n  <main>\n    <section>\n      <h1>First section</h1>\n    </section>\n\n    <section>\n      <h2>Second section</h2>\n    </section>\n    <section>\n      <h3>Third section</h3>\n    </section>\n  </main>\n</template>\n\n<style scoped>\n.fixed {\n  position: fixed;\n  top: 0;\n  right: 0;\n}\n.scroll {\n  height: 200vh;\n}\n.container {\n  height: 50vh;\n  overflow: scroll;\n}\nmain {\n  background-color: transparent;\n}\nsection {\n  min-height: 100vh;\n  display: grid;\n  place-items: center;\n  outline: 1px solid red;\n}\nh1,\nh2,\nh3 {\n  color: #f7f7f7;\n}\n</style>\n"
  },
  {
    "path": "playground/vue/src/pages/controls/TransformControlsDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { OrbitControls, TransformControls } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { TresLeches, useControls } from '@tresjs/leches'\nimport { BasicShadowMap, NoToneMapping, SRGBColorSpace } from 'three'\nimport { reactive, ref } from 'vue'\nimport type { TransformControlsProps } from '../../../../src/core/controls/TransformControls.vue'\nimport '@tresjs/leches/styles'\n\nconst gl = {\n  clearColor: '#82DBC5',\n  shadows: true,\n  alpha: false,\n  shadowMapType: BasicShadowMap,\n  outputColorSpace: SRGBColorSpace,\n  toneMapping: NoToneMapping,\n}\n\nconst boxRef = ref()\nconst sphereRef = ref()\n\nconst transformRef = ref()\n\nfunction changeObject(object: any) {\n  transformRef.value = object\n}\n\nconst context = ref()\n\nconst controlsState = reactive<Partial<TransformControlsProps>>({\n  mode: 'translate',\n  enabled: true,\n  space: 'world',\n  axis: 'XYZ',\n  size: 1,\n  showX: true,\n  showY: true,\n  showZ: true,\n})\n\nuseControls('fpsgraph')\n\nconst { mode, enabled, space, axis, size, showX, showY, showZ } = useControls({\n  mode: {\n    label: 'Mode',\n    value: controlsState.mode,\n    options: ['translate', 'rotate', 'scale'],\n  },\n  enabled: controlsState.enabled,\n  space: {\n    label: 'Space',\n    value: controlsState.space,\n    options: ['world', 'local'],\n  },\n  axis: {\n    label: 'Axis',\n    value: controlsState.axis,\n    options: ['X', 'Y', 'Z', 'XY', 'YZ', 'XZ', 'XYZ'],\n  },\n  size: {\n    label: 'Size',\n    value: controlsState.size,\n    min: 0,\n    max: 10,\n    step: 0.01,\n  },\n  showX: true,\n  showY: true,\n  showZ: true,\n})\n\nwatch([mode.value, enabled.value, space.value, axis.value, size.value, showX.value, showY.value, showZ.value], () => {\n  controlsState.mode = mode.value.value\n  controlsState.enabled = enabled.value.value\n  controlsState.space = space.value.value\n  controlsState.axis = axis.value.value\n  controlsState.size = size.value.value\n  controlsState.showX = showX.value.value\n  controlsState.showY = showY.value.value\n  controlsState.showZ = showZ.value.value\n})\n</script>\n\n<template>\n  <TresLeches />\n  <TresCanvas\n    v-bind=\"gl\"\n    ref=\"context\"\n  >\n    <TresPerspectiveCamera :position=\"[11, 11, 11]\" :look-at=\"[0, 0, 0]\" />\n    <OrbitControls make-default />\n\n    <TresMesh\n      ref=\"boxRef\"\n      :position=\"[-2, 1, 0]\"\n      @click=\"changeObject(boxRef)\"\n    >\n      <TresBoxGeometry />\n      <TresMeshNormalMaterial />\n    </TresMesh>\n    <TransformControls\n      v-if=\"transformRef\"\n      :object=\"transformRef\"\n      v-bind=\"controlsState\"\n    />\n    <TresMesh\n      ref=\"sphereRef\"\n      :position=\"[2, 1, 0]\"\n      @click=\"changeObject(sphereRef)\"\n    >\n      <TresSphereGeometry />\n      <TresMeshNormalMaterial />\n    </TresMesh>\n    <TresAmbientLight :intensity=\"1\" />\n    <TresGridHelper />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/index.vue",
    "content": "<script setup lang=\"ts\">\nimport {\n  abstractionsRoutes,\n  controlsRoutes,\n  loadersRoutes,\n  materialsRoutes,\n  miscRoutes,\n  shapesRoutes,\n  stagingRoutes,\n} from '../router/routes'\n\nconst sections = [\n  { icon: '📦', title: 'Abstractions', routes: abstractionsRoutes },\n  { icon: '🕹️', title: 'Controls', routes: controlsRoutes },\n  { icon: '🎭', title: 'Staging', routes: stagingRoutes },\n  { icon: '⏳', title: 'Loaders', routes: loadersRoutes },\n  { icon: '👔', title: 'Materials', routes: materialsRoutes },\n  { icon: '🔷', title: 'Shapes', routes: shapesRoutes },\n  { icon: '🛠️', title: 'Misc', routes: miscRoutes },\n]\n</script>\n\n<template>\n  <div\n    class=\"\n  container mx-auto max-w-3xl\n  font-sans text-xs color-gray\n  bg-white\n  \"\n  >\n    <div class=\"mx-4\">\n      <div\n        class=\"\n    mt-24 mb-12 text-center align-baseline items-center gap-6\n    sm:mt-16 sm:mb-6 sm:text-left sm:flex sm:flex-row-reverse\n    \"\n      >\n        <div>\n          <img\n            src=\"/logo.svg\"\n            alt=\"Cientos logo\"\n            class=\"max-w-36 sm:max-w-xs align-baseline\"\n          />\n        </div>\n        <div class=\"sm:w-2/3\">\n          <h1\n            class=\"\n        w-auto max-w-75 mx-auto text-5xl text-zinc-700 mb-3\n        sm:mx-none sm:w-1/2 sm:max-w-72\n        \"\n          >\n            <span class=\"text-cientos-blue\">Cientos</span> Playground\n          </h1>\n          <p class=\"text-lg\">\n            Testing zone for TresJS/Cientos components\n          </p>\n        </div>\n      </div>\n      <div class=\"text-center sm:text-left sm:grid sm:grid-cols-2 md:grid-cols-3 gap-4\">\n        <div\n          v-for=\"{ title, routes, icon } in sections\"\n          :key=\"title\"\n          class=\"\n          p-4 my-4 leading-normal size-m weight-600 bg-zinc-50 rounded\n          sm:my-0\n          \"\n        >\n          <div class=\"inline-block p-2 p-x-3 m-b-3 text-2xl bg-zinc-200 rounded\">\n            {{ icon }}\n          </div>\n          <h2 class=\"text-sm p-0 m-0 mb-1.5 font-semibold text-zinc-600\">\n            {{ title }}\n          </h2>\n          <div\n            v-for=\"route in routes\"\n            :key=\"route.name\"\n            class=\"link-wrapper\"\n          >\n            <router-link\n              class=\"no-underline text-zinc-700 visited:text-zinc-400 hover:text-cientos-blue\"\n              :to=\"route.path\"\n            >\n              <span>{{ route.name }} </span>\n            </router-link>\n          </div>\n        </div>\n      </div>\n    </div>\n  </div>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/loaders/SVGDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { OrbitControls, SVG } from '@tresjs/cientos'\nimport { TresCanvas, useRenderLoop } from '@tresjs/core'\nimport { NoToneMapping } from 'three'\nimport { shallowRef } from 'vue'\n\nconst svgTriangleString = `<svg width=\"404\" height=\"80\" viewBox=\"0 0 404 80\" fill=\"none\" \nxmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M44.5703 5.71662C46.124 3.12726 49.8767 3.12726 51.4303 5.71662L92.3655 73.942C93.9652 \n76.6081 92.0447 80 88.9355 80H7.06507C3.95589 80 2.03544 76.6081 3.6351 73.942L44.5703 5.71662Z\" \nfill=\"rgb(130,219,197)\" stroke=\"rgb(130,219,197)\" />\n</svg>`\n\nconst svgSquareString = `<svg width=\"404\" height=\"80\" viewBox=\"0 0 404 80\" \nfill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<rect x=\"172\" y=\"2.64999\" width=\"74.7\" height=\"74.7\" rx=\"4\" fill=\"rgb(79,79,79)\" stroke=\"rgb(79,79,79)\" />\n</svg>`\n\nconst svgHeartURL = '/cientos.svg'\n\nconst { onLoop } = useRenderLoop()\n\nconst skipFillsA = shallowRef(false)\nconst skipFillsB = shallowRef(true)\nconst skipFillsC = shallowRef(false)\n\nlet cooldown = 0\n\nonLoop(({ delta }) => {\n  cooldown -= delta\n  while (cooldown <= 0) {\n    const skipFillsTmp = skipFillsA.value\n    skipFillsA.value = skipFillsC.value\n    skipFillsC.value = skipFillsB.value\n    skipFillsB.value = skipFillsTmp\n    cooldown += 1\n  }\n})\n\nconst gl = {\n  clearColor: '#333',\n  alpha: true,\n  toneMapping: NoToneMapping,\n}\n</script>\n\n<template>\n  <TresCanvas\n    v-bind=\"gl\"\n    render-mode=\"on-demand\"\n  >\n    <TresPerspectiveCamera :position=\"[0, 2, 10]\" />\n    <TresGridHelper :args=\"[10, 10]\" />\n    <TresGroup\n      :scale=\"0.01\"\n      :position=\"[-2.1, 1, 0]\"\n    >\n      <Suspense>\n        <SVG\n          :src=\"svgTriangleString\"\n          :skip-fills=\"skipFillsA\"\n        />\n      </Suspense>\n      <Suspense>\n        <SVG\n          :src=\"svgSquareString\"\n          :skip-fills=\"skipFillsB\"\n        />\n      </Suspense>\n      <Suspense>\n        <SVG\n          :src=\"svgHeartURL\"\n          :skip-fills=\"skipFillsC\"\n          :position=\"[321.5, -4, 0]\"\n        />\n      </Suspense>\n      <Suspense>\n        <SVG\n          :src=\"svgHeartURL\"\n          :skip-fills=\"skipFillsC\"\n          :position=\"[321.5, -4, 0]\"\n        />\n      </Suspense>\n    </TresGroup>\n    <TresAmbientLight />\n    <TresDirectionalLight />\n    <OrbitControls />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/loaders/UseFBXDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { OrbitControls } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { BasicShadowMap, NoToneMapping, SRGBColorSpace } from 'three'\nimport Jeep from '../../components/fbx/Jeep.vue'\n\nconst gl = {\n  clearColor: '#82DBC5',\n  shadows: true,\n  alpha: false,\n  shadowMapType: BasicShadowMap,\n  outputColorSpace: SRGBColorSpace,\n  toneMapping: NoToneMapping,\n}\n</script>\n\n<template>\n  <TresCanvas v-bind=\"gl\">\n    <TresPerspectiveCamera :position=\"[5.3, 2.45, 9.3]\" :look-at=\"[0, 0, 0]\" />\n    <OrbitControls />\n    <Suspense>\n      <Jeep />\n    </Suspense>\n    <TresMesh\n      :rotate-x=\"Math.PI * -0.5\"\n      :position-y=\"-2\"\n      receive-shadow\n    >\n      <TresPlaneGeometry :args=\"[40, 40]\" />\n      <TresMeshStandardMaterial :color=\"0xF7F7F7\" />\n    </TresMesh>\n    <TresAmbientLight :intensity=\"1\" />\n    <TresDirectionalLight\n      :intensity=\"1\"\n      cast-shadow\n      :position=\"[5, 10, 5]\"\n    />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/loaders/use-fbx/FBXModelDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { FBXModel, OrbitControls } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { BasicShadowMap, NoToneMapping, SRGBColorSpace } from 'three'\n\nconst gl = {\n  clearColor: '#82DBC5',\n  shadows: true,\n  alpha: false,\n  shadowMapType: BasicShadowMap,\n  outputColorSpace: SRGBColorSpace,\n  toneMapping: NoToneMapping,\n}\n</script>\n\n<template>\n  <TresCanvas v-bind=\"gl\">\n    <TresPerspectiveCamera :position=\"[5.3, 2.45, 9.3]\" :look-at=\"[0, 0, 0]\" />\n    <OrbitControls />\n    <FBXModel\n      path=\"https://raw.githubusercontent.com/Tresjs/assets/main/models/fbx/low-poly-truck/Jeep_done.fbx\"\n      cast-shadow\n      :scale=\"0.01\"\n      :position=\"[0, -1.6, 0]\"\n      :rotation-y=\"-Math.PI * 0.5\"\n    />\n    <TresMesh\n      :rotate-x=\"Math.PI * -0.5\"\n      :position-y=\"-2\"\n      receive-shadow\n    >\n      <TresPlaneGeometry :args=\"[40, 40]\" />\n      <TresMeshStandardMaterial :color=\"0xF7F7F7\" />\n    </TresMesh>\n    <TresAmbientLight :intensity=\"1\" />\n    <TresDirectionalLight\n      :intensity=\"1\"\n      cast-shadow\n      :position=\"[5, 10, 5]\"\n    />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/loaders/use-fbx/TheModel.vue",
    "content": "<script setup lang=\"ts\">\n/* eslint-disable no-console */\nimport { useFBX } from '@tresjs/cientos'\nimport { Mesh } from 'three'\n\n// Inject the shared state for loading progress\nconst state = inject<{\n  hasFinishLoading: boolean\n  progress: number\n}>('fbx-loader-state')!\n\n// Use the new reactive useFBX composable\nconst { state: model, isLoading, nodes, materials } = useFBX(\n  'https://raw.githubusercontent.com/Tresjs/assets/main/models/fbx/low-poly-truck/Jeep_done.fbx',\n)\n\n// Log nodes when they become available\nwatch(nodes, (newNodes) => {\n  console.log('FBX nodes', newNodes)\n})\n\n// Log materials when they become available\nwatch(materials, (newMaterials) => {\n  console.log('FBX materials', newMaterials)\n})\n\n// Handle model loading and apply transformations\nwatch(model, (newModel) => {\n  if (newModel) {\n    console.log('FBX model loaded', newModel)\n\n    // Apply transformations and shadow settings\n    newModel.scale.set(0.01, 0.01, 0.01)\n    newModel.position.set(0, -2.6, 0) // Adjusted for TresGroup position offset\n    newModel.rotation.y = -Math.PI * 0.5\n\n    // Enable shadows for all meshes\n    newModel.traverse((child) => {\n      if (child instanceof Mesh) {\n        child.castShadow = true\n      }\n    })\n\n    // Simulate loading completion after model is ready\n    setTimeout(() => {\n      state.hasFinishLoading = true\n    }, 500)\n  }\n}, { immediate: true })\n\n// Track loading state\nwatch(isLoading, (loading) => {\n  console.log('FBX loading state:', loading)\n  if (!loading && model.value) {\n    state.progress = 100\n  }\n  else {\n    state.progress = 0\n  }\n}, { immediate: true })\n</script>\n\n<template>\n  <primitive v-if=\"model && !isLoading\" :object=\"model\" />\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/loaders/use-fbx/index.vue",
    "content": "<script setup lang=\"ts\">\nimport { OrbitControls } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { BasicShadowMap, NoToneMapping, SRGBColorSpace } from 'three'\nimport TheModel from './TheModel.vue'\n\nconst gl = {\n  clearColor: '#82DBC5',\n  shadows: true,\n  alpha: false,\n  shadowMapType: BasicShadowMap,\n  outputColorSpace: SRGBColorSpace,\n  toneMapping: NoToneMapping,\n}\n\nconst state = reactive({\n  hasFinishLoading: false,\n  progress: 0,\n})\n\nprovide('fbx-loader-state', state)\n</script>\n\n<template>\n  <Transition\n    name=\"fade-overlay\"\n    enter-active-class=\"opacity-1 transition-opacity duration-200\"\n    leave-active-class=\"opacity-0 transition-opacity duration-200\"\n  >\n    <div\n      v-show=\"!state.hasFinishLoading\"\n      class=\"absolute bg-white t-0 l-0 w-full h-full z-20 flex justify-center items-center text-black font-mono\"\n    >\n      <div class=\"w-200px text-center\">\n        <div>Loading FBX Model...</div>\n        <div class=\"mt-2\">{{ Math.round(state.progress) }}%</div>\n      </div>\n    </div>\n  </Transition>\n  <TresCanvas v-bind=\"gl\">\n    <TresPerspectiveCamera :position=\"[5.3, 2.45, 9.3]\" :look-at=\"[0, 0, 0]\" />\n    <OrbitControls />\n    <TresGroup :position=\"[0, 1, 0]\">\n      <TheModel />\n    </TresGroup>\n    <TresMesh\n      :rotate-x=\"Math.PI * -0.5\"\n      :position-y=\"-2\"\n      receive-shadow\n    >\n      <TresPlaneGeometry :args=\"[40, 40]\" />\n      <TresMeshStandardMaterial :color=\"0xF7F7F7\" />\n    </TresMesh>\n    <TresAmbientLight :intensity=\"1\" />\n    <TresDirectionalLight\n      :intensity=\"1\"\n      cast-shadow\n      :position=\"[5, 10, 5]\"\n    />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/loaders/use-gltf/GLTFModelDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { GLTFModel, OrbitControls } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { BasicShadowMap, NoToneMapping, SRGBColorSpace } from 'three'\n\nconst gl = {\n  clearColor: '#82DBC5',\n  shadows: true,\n  alpha: false,\n  shadowMapType: BasicShadowMap,\n  outputColorSpace: SRGBColorSpace,\n  toneMapping: NoToneMapping,\n}\n</script>\n\n<template>\n  <TresCanvas v-bind=\"gl\">\n    <TresPerspectiveCamera :position=\"[5.3, 2.45, 9.3]\" :look-at=\"[0, 0, 0]\" />\n    <OrbitControls />\n    <GLTFModel\n      path=\"https://raw.githubusercontent.com/Tresjs/assets/main/models/gltf/blender-cube.glb\"\n      cast-shadow\n      :position=\"[0, 1, 0]\"\n    />\n    <TresMesh\n      :rotate-x=\"Math.PI * -0.5\"\n      receive-shadow\n    >\n      <TresPlaneGeometry :args=\"[40, 40]\" />\n      <TresMeshStandardMaterial :color=\"0xF7F7F7\" />\n    </TresMesh>\n    <TresAmbientLight :intensity=\"1\" />\n    <TresDirectionalLight\n      :intensity=\"1\"\n      cast-shadow\n      :position=\"[5, 10, 5]\"\n    />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/loaders/use-gltf/TheModel.vue",
    "content": "<script setup lang=\"ts\">\n/* eslint-disable no-console */\nimport { useGLTF } from '@tresjs/cientos'\n\nconst state = inject<{\n  hasFinishLoading: boolean\n  progress: number\n}>('gltf-loader-state')!\n\nconst { state: model, progress, nodes, materials } = useGLTF(\n  '/blender-cube-draco.glb',\n  { draco: true },\n)\n\nwatch(nodes, (newNodes) => {\n  console.log('nodes', newNodes)\n})\n\nwatch(materials, (newMaterials) => {\n  console.log('materials', newMaterials)\n})\n\nwatch(model, (newModel) => {\n  console.log('model', newModel)\n  setTimeout(() => {\n    state.hasFinishLoading = true\n  }, 1000)\n})\n\nwatch(progress, (newProgress) => {\n  console.log('progress', newProgress)\n  state.progress = newProgress.percentage\n}, { immediate: true })\n</script>\n\n<template>\n  <primitive v-if=\"nodes.BlenderCube\" :object=\"nodes.BlenderCube\" />\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/loaders/use-gltf/index.vue",
    "content": "<script setup lang=\"ts\">\nimport { OrbitControls } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport TheModel from './TheModel.vue'\n\nconst gl = {\n  clearColor: '#82DBC5',\n  shadows: true,\n}\n\nconst state = reactive({\n  hasFinishLoading: false,\n  progress: 0,\n})\n\nprovide('gltf-loader-state', state)\n</script>\n\n<template>\n  <Transition\n    name=\"fade-overlay\"\n    enter-active-class=\"opacity-1 transition-opacity duration-200\"\n    leave-active-class=\"opacity-0 transition-opacity duration-200\"\n  >\n    <div\n      v-show=\"!state.hasFinishLoading\"\n      class=\"absolute bg-white t-0 l-0 w-full h-full z-20 flex justify-center items-center text-black font-mono\"\n    >\n      <div class=\"w-200px\">\n        Loading...\n        {{ state.progress }} %\n      </div>\n    </div>\n  </Transition>\n  <TresCanvas v-bind=\"gl\">\n    <TresPerspectiveCamera :position=\"[5.3, 2.45, 9.3]\" :look-at=\"[0, 0, 0]\" />\n    <OrbitControls />\n    <TresGroup :position=\"[0, 1, 0]\">\n      <TheModel />\n    </TresGroup>\n    <TresMesh\n      :rotate-x=\"Math.PI * -0.5\"\n      receive-shadow\n    >\n      <TresPlaneGeometry :args=\"[40, 40]\" />\n      <TresMeshStandardMaterial :color=\"0xF7F7F7\" />\n    </TresMesh>\n    <TresAmbientLight :intensity=\"1\" />\n    <TresDirectionalLight\n      :intensity=\"1\"\n      cast-shadow\n      :position=\"[5, 10, 5]\"\n    />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/loaders/use-svg/SVGModelDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { TresCanvas } from '@tresjs/core'\nimport { OrbitControls, UseSVG } from '@tresjs/cientos'\nimport { onMounted, onUnmounted, shallowRef } from 'vue'\n\n// SVG data for demo\nconst svgTriangleString = `<svg width=\"404\" height=\"80\" viewBox=\"0 0 404 80\" fill=\"none\" \nxmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M44.5703 5.71662C46.124 3.12726 49.8767 3.12726 51.4303 5.71662L92.3655 73.942C93.9652 \n76.6081 92.0447 80 88.9355 80H7.06507C3.95589 80 2.03544 76.6081 3.6351 73.942L44.5703 5.71662Z\" \nfill=\"rgb(130,219,197)\" stroke=\"rgb(130,219,197)\" />\n</svg>`\n\nconst svgSquareString = `<svg width=\"404\" height=\"80\" viewBox=\"0 0 404 80\" \nfill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<rect x=\"172\" y=\"2.64999\" width=\"74.7\" height=\"74.7\" rx=\"4\" fill=\"rgb(79,79,79)\" stroke=\"rgb(79,79,79)\" />\n</svg>`\n\nconst svgHeartURL = '/cientos.svg'\n\n// Animation state for the demo\nconst skipFillsA = shallowRef(false)\nconst skipFillsB = shallowRef(true)\nconst skipFillsC = shallowRef(false)\n\nlet animationId: number\nlet cooldown = 0\n\n/**\n * Animation loop that cycles through different skip-fills states\n * to demonstrate the reactivity of the SVG component\n */\nconst animate = (deltaTime: number) => {\n  cooldown -= deltaTime\n\n  while (cooldown <= 0) {\n    // Cycle through different states\n    const skipFillsTmp = skipFillsA.value\n    skipFillsA.value = skipFillsC.value\n    skipFillsC.value = skipFillsB.value\n    skipFillsB.value = skipFillsTmp\n    cooldown += 1000 // 1 second interval\n  }\n\n  animationId = requestAnimationFrame(_time => animate(16.67)) // ~60fps\n}\n\nonMounted(() => {\n  animate(0)\n})\n\nonUnmounted(() => {\n  if (animationId) {\n    cancelAnimationFrame(animationId)\n  }\n})\n</script>\n\n<template>\n  <TresCanvas\n    clear-color=\"#333\"\n    render-mode=\"on-demand\"\n  >\n    <TresPerspectiveCamera :position=\"[0, 2, 10]\" />\n    <TresGridHelper :args=\"[10, 10]\" />\n    <OrbitControls />\n\n    <TresGroup\n      :scale=\"0.01\"\n      :position=\"[1, 1, 0]\"\n    >\n      <!-- Triangle SVG with animated skip-fills -->\n\n      <UseSVG\n        :src=\"svgTriangleString\"\n        :skip-fills=\"skipFillsA\"\n        :position=\"[-200, 0, 0]\"\n        :fill-material=\"{ transparent: true, opacity: 0.8 }\"\n      />\n\n      <!-- Square SVG with animated skip-fills -->\n\n      <UseSVG\n        :src=\"svgSquareString\"\n        :skip-fills=\"skipFillsB\"\n        :position=\"[0, 200, 0]\"\n        :stroke-material=\"{ transparent: true, opacity: 0.9 }\"\n      />\n\n      <!-- Heart SVG from URL with animated skip-fills -->\n\n      <UseSVG\n        :src=\"svgHeartURL\"\n        :skip-fills=\"skipFillsC\"\n        :position=\"[200, -4, 0]\"\n        :fill-material=\"{ color: '#ff6b6b', transparent: true, opacity: 0.7 }\"\n        depth=\"offsetZ\"\n      />\n\n      <!-- Duplicate heart to show multiple instances -->\n\n      <UseSVG\n        :src=\"svgHeartURL\"\n        :skip-fills=\"skipFillsC\"\n        :position=\"[200, -80, 0]\"\n        :fill-material=\"{ color: '#4ecdc4', transparent: true, opacity: 0.7 }\"\n        depth=\"renderOrder\"\n      />\n    </TresGroup>\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/loaders/use-svg/TheModel.vue",
    "content": "<script setup lang=\"ts\">\nimport { Text3D, useSVG } from '@tresjs/cientos'\nimport { shallowRef, watch } from 'vue'\n\n// SVG data for demo\nconst svgTriangleString = `<svg width=\"404\" height=\"80\" viewBox=\"0 0 404 80\" fill=\"none\" \nxmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M44.5703 5.71662C46.124 3.12726 49.8767 3.12726 51.4303 5.71662L92.3655 73.942C93.9652 \n76.6081 92.0447 80 88.9355 80H7.06507C3.95589 80 2.03544 76.6081 3.6351 73.942L44.5703 5.71662Z\" \nfill=\"rgb(130,219,197)\" stroke=\"rgb(130,219,197)\" />\n</svg>`\n\nconst svgSquareString = `<svg width=\"404\" height=\"80\" viewBox=\"0 0 404 80\" \nfill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<rect x=\"172\" y=\"2.64999\" width=\"74.7\" height=\"74.7\" rx=\"4\" fill=\"rgb(79,79,79)\" stroke=\"rgb(79,79,79)\" />\n</svg>`\n\n// Demo state\nconst currentSVG = shallowRef(svgTriangleString)\nconst skipFills = shallowRef(false)\n\n// Use the useSVG composable\nconst { state, isLoading, layers, dispose } = useSVG(currentSVG, {\n  skipFills: skipFills.value,\n  fillMaterial: { transparent: true, opacity: 0.8 },\n  strokeMaterial: { transparent: true, opacity: 0.9 },\n  depth: 'renderOrder',\n})\n\n// Animation logic - switch between SVGs\nconst SWITCH_INTERVAL = 3000 // 3 seconds\n\n// Watch for reactive updates to skipFills\nwatch(skipFills, (_newValue) => {\n  // Re-call useSVG with new options when skipFills changes\n  // Note: In a real scenario you might want to make this more reactive\n})\n\n// Switch between different SVGs for demo\nconst switchSVG = () => {\n  if (currentSVG.value === svgTriangleString) {\n    currentSVG.value = svgSquareString\n  }\n  else {\n    currentSVG.value = svgTriangleString\n  }\n  skipFills.value = !skipFills.value\n}\n\n// Auto-switch for demo\nsetInterval(switchSVG, SWITCH_INTERVAL)\n\ndefineExpose({\n  state,\n  layers,\n  dispose,\n})\n</script>\n\n<template>\n  <TresGroup\n    v-if=\"!isLoading && layers.length > 0\"\n    :scale=\"0.01\"\n    :position=\"[-1, 1, 0]\"\n  >\n    <!-- Render the SVG layers manually using the composable -->\n    <TresMesh\n      v-for=\"(layer, index) in layers\"\n      :key=\"`layer-${index}`\"\n      :geometry=\"layer.geometry\"\n      :render-order=\"index\"\n    >\n      <TresMeshBasicMaterial v-bind=\"layer.material\" />\n    </TresMesh>\n\n    <!-- Info text -->\n    <TresGroup :position=\"[0, -100, 0]\">\n      <Text3D\n        text=\"useSVG Composable Demo\"\n        :size=\"20\"\n        :height=\"2\"\n        font=\"/fonts/helvetiker_regular.typeface.json\"\n      />\n    </TresGroup>\n  </TresGroup>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/loaders/use-svg/index.vue",
    "content": "<script setup lang=\"ts\">\nimport { OrbitControls } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport TheModel from './TheModel.vue'\n</script>\n\n<template>\n  <div class=\"w-full h-full relative\">\n    <TresCanvas\n      clear-color=\"#333\"\n      render-mode=\"on-demand\"\n    >\n      <TresPerspectiveCamera :position=\"[0, 2, 10]\" />\n      <TresGridHelper :args=\"[10, 10]\" />\n\n      <!-- Show different demos based on mode -->\n      <TheModel />\n\n      <TresAmbientLight />\n      <TresDirectionalLight />\n      <OrbitControls />\n    </TresCanvas>\n  </div>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/loaders/use-texture/PBRTextures.vue",
    "content": "<script setup lang=\"ts\">\n/* eslint-disable no-console */\nimport { TresCanvas } from '@tresjs/core'\nimport { Environment, OrbitControls, useGLTF, useTextures } from '@tresjs/cientos'\nimport type { MeshStandardMaterial } from 'three'\n\n// Load the 3D model\nconst { nodes, materials } = useGLTF('https://raw.githubusercontent.com/Tresjs/assets/main/models/gltf/blender-cube.glb', { draco: true })\nconst cube = computed(() => nodes.value?.BlenderCube)\nconst material = computed(() => materials.value?.Material)\n\n// Define texture paths\nconst texturePaths = [\n  'https://raw.githubusercontent.com/Tresjs/assets/main/textures/rusted-metal/Metal053C_4K-JPG_Color.jpg',\n  'https://raw.githubusercontent.com/Tresjs/assets/main/textures/rusted-metal/Metal053C_4K-JPG_NormalGL.jpg',\n  'https://raw.githubusercontent.com/Tresjs/assets/main/textures/rusted-metal/Metal053C_4K-JPG_Roughness.jpg',\n  'https://raw.githubusercontent.com/Tresjs/assets/main/textures/rusted-metal/Metal053C_4K-JPG_Metalness.jpg',\n  'https://raw.githubusercontent.com/Tresjs/assets/main/textures/rusted-metal/Metal053C_4K-JPG_Displacement.jpg',\n]\n\n// Load all PBR textures at once\nconst { textures, isLoading, error } = useTextures(texturePaths)\n\n// Apply textures to material when loaded\nwatch([material, textures], ([modelMaterial, textures]) => {\n  if (modelMaterial && textures && textures.length === texturePaths.length) {\n    // Cast to MeshStandardMaterial to access PBR properties\n    const pbrMaterial = modelMaterial as MeshStandardMaterial\n\n    // Apply textures\n    pbrMaterial.map = textures[0]\n    pbrMaterial.normalMap = textures[1]\n    pbrMaterial.roughnessMap = textures[2]\n    pbrMaterial.metalnessMap = textures[3]\n    pbrMaterial.displacementMap = textures[4]\n\n    // Set material properties\n    pbrMaterial.displacementScale = 0\n    pbrMaterial.metalness = 0.8\n    pbrMaterial.roughness = 0.2\n  }\n})\n\n// Log loading state and errors\nwatch(isLoading, (_loading) => {\n  // Only log errors, not loading state\n  console.log('isLoading', _loading)\n}, { immediate: true })\n\nwatch(error, (errs) => {\n  if (errs) {\n    console.error('Error loading textures:', errs)\n  }\n})\n</script>\n\n<template>\n  <Transition\n    name=\"fade-overlay\"\n    enter-active-class=\"opacity-1 transition-opacity duration-200\"\n    leave-active-class=\"opacity-0 transition-opacity duration-200\"\n  >\n    <div\n      v-show=\"isLoading\"\n      class=\"absolute bg-white t-0 l-0 w-full h-full z-20 flex justify-center items-center text-black font-mono\"\n    >\n      <div class=\"w-200px\">\n        Loading...\n      </div>\n    </div>\n  </Transition>\n  <TresCanvas clear-color=\"#4f4f4f\">\n    <Suspense>\n      <Environment preset=\"studio\" background :blur=\"1\" />\n    </Suspense>\n    <TresPerspectiveCamera :position=\"[8, 8, 8]\" />\n    <OrbitControls />\n    <TresGridHelper />\n    <TresAmbientLight :intensity=\"2\" />\n    <TresGroup position-y=\"2\">\n      <primitive v-if=\"cube\" :object=\"cube\" />\n    </TresGroup>\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/loaders/use-texture/TheExperience.vue",
    "content": "<script setup lang=\"ts\">\n/* eslint-disable no-console */\nimport { OrbitControls, useTexture } from '@tresjs/cientos'\n\nconst state = inject<{\n  hasFinishLoading: boolean\n  progress: number\n}>('gltf-loader-state')!\n\nconst { state: texture, isLoading } = useTexture(\n  'https://raw.githubusercontent.com/Tresjs/assets/main/textures/black-rock/Rock035_2K_Color.jpg',\n)\n\nwatch(isLoading, (newIsLoading) => {\n  console.log('isLoading', newIsLoading)\n  if (newIsLoading) {\n    state.hasFinishLoading = false\n  }\n}, { immediate: true })\n\nwatch(texture, (newTexture) => {\n  console.log('texture', newTexture)\n  setTimeout(() => {\n    state.hasFinishLoading = true\n  }, 1000)\n}, { immediate: true })\n</script>\n\n<template>\n  <TresPerspectiveCamera :position=\"[3, 3, 3]\" />\n  <OrbitControls />\n  <TresGridHelper />\n  <TresAmbientLight :intensity=\"1\" />\n  <TresMesh>\n    <TresSphereGeometry />\n    <TresMeshStandardMaterial :map=\"texture\" />\n  </TresMesh>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/loaders/use-texture/UseTextureComponent.vue",
    "content": "<script setup lang=\"ts\">\n/* eslint-disable no-console */\nimport { TresCanvas } from '@tresjs/core'\nimport { OrbitControls, UseTexture } from '@tresjs/cientos'\nimport type { Texture } from 'three'\n\nconst path = 'https://raw.githubusercontent.com/Tresjs/assets/main/textures/black-rock/Rock035_2K_Color.jpg'\n\nconst handleLoaded = (texture: Texture) => {\n  console.log('Loaded texture', texture)\n}\n\nconst handleError = (error: unknown) => {\n  console.error('error', error)\n}\n</script>\n\n<template>\n  <TresCanvas clear-color=\"#C0ffee\">\n    <TresPerspectiveCamera :position=\"[3, 3, 3]\" />\n    <OrbitControls />\n    <TresGridHelper />\n    <TresAmbientLight :intensity=\"1\" />\n    <UseTexture v-slot=\"{ state: texture }\" :path=\"path\" @loaded=\"handleLoaded\" @error=\"handleError\">\n      <TresMesh>\n        <TresSphereGeometry />\n        <TresMeshStandardMaterial :map=\"texture\" />\n      </TresMesh>\n    </UseTexture>\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/loaders/use-texture/index.vue",
    "content": "<script setup lang=\"ts\">\nimport { TresCanvas } from '@tresjs/core'\n\nimport TheExperience from './TheExperience.vue'\n\nconst state = reactive({\n  hasFinishLoading: false,\n  progress: 0,\n})\n\nprovide('gltf-loader-state', state)\n</script>\n\n<template>\n  <div class=\"relative h-full w-full\">\n    <Transition\n      name=\"fade-overlay\"\n      enter-active-class=\"opacity-1 transition-opacity duration-200\"\n      leave-active-class=\"opacity-0 transition-opacity duration-200\"\n    >\n      <div\n        v-show=\"!state.hasFinishLoading\"\n        class=\"absolute bg-white t-0 l-0 w-full h-full z-20 flex justify-center items-center text-black font-mono\"\n      >\n        <div class=\"w-200px\">\n          Loading...\n          {{ state.progress }} %\n        </div>\n      </div>\n    </Transition>\n    <TresCanvas clear-color=\"#C0ffee\">\n      <TheExperience />\n    </TresCanvas>\n  </div>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/loaders/useVideoTextureDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { OrbitControls, Sphere, useVideoTexture } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { NoToneMapping, SRGBColorSpace } from 'three'\nimport { ref } from 'vue'\n\nconst gl = {\n  clearColor: '#333',\n  alpha: true,\n  outputColorSpace: SRGBColorSpace,\n  toneMapping: NoToneMapping,\n  useLegacyLights: false,\n}\n\nconst exampleVideo = 'https://raw.githubusercontent.com/Tresjs/assets/main/textures/video-textures/useVideoTexture.mp4'\n\nconst texture = ref()\n\ntexture.value = await useVideoTexture(exampleVideo, { loop: false })\n</script>\n\n<template>\n  <TresCanvas\n    v-bind=\"gl\"\n  >\n    <TresPerspectiveCamera :position=\"[0, 2, 5]\" />\n    <OrbitControls />\n    <Sphere :position=\"[0, 2, 0]\">\n      <TresMeshBasicMaterial :map=\"texture\" />\n    </Sphere>\n    <TresGridHelper\n      :size=\"10\"\n      :divisions=\"10\"\n    />\n    <TresAmbientLight :intensity=\"1\" />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/materials/CustomShaderMaterialDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport {\n  CustomShaderMaterial,\n  OrbitControls,\n  StatsGl,\n  useTexture,\n} from '@tresjs/cientos'\nimport { TresCanvas, useRenderLoop } from '@tresjs/core'\nimport { TresLeches, useControls } from '@tresjs/leches'\nimport { MeshMatcapMaterial } from 'three'\n\nimport { nextTick, onMounted } from 'vue'\nimport '@tresjs/leches/styles'\n\nconst { onLoop } = useRenderLoop()\n\nconst gl = {\n  clearColor: '#82DBC5',\n}\n\nconst { state: texture01 } = useTexture('/matcap_01.png')\n\nconst materialProps = {\n  baseMaterial: MeshMatcapMaterial,\n  matcap: texture01.value,\n  fragmentShader: `\n    varying float vWobble;\n\n    uniform float u_Time;\n\n    void main() {\n      float wobble = vWobble * 0.5 + 0.5;\n      vec4 csm_DiffuseColor2 = mix(vec4(0.0, 0.0, 0.0, 1.0), vec4(1.0, 0.0, 2.0, 1.0), wobble);\n      csm_DiffuseColor = mix(csm_DiffuseColor, csm_DiffuseColor2, wobble);\n    }\n  `,\n  vertexShader: `\n    uniform float u_Time;\n    uniform float u_WobbleSpeed;\n    uniform float u_WobbleAmplitude;\n    uniform float u_WobbleFrequency;\n\n    varying float vWobble;\n\n    void main() {\n      float wobble = sin(csm_Position.z * u_WobbleFrequency + u_Time * u_WobbleSpeed);\n      csm_Position += normal * wobble * u_WobbleAmplitude;\n\n      vWobble = wobble;\n    }\n  `,\n  uniforms: {\n    u_Time: { value: 0 },\n    u_WobbleSpeed: { value: 3 },\n    u_WobbleAmplitude: { value: 0.07 },\n    u_WobbleFrequency: { value: 3 },\n  },\n}\n\nonMounted(async () => {\n  await nextTick()\n\n  onLoop(() => {\n    materialProps.uniforms.u_Time.value\n      += 0.01 * materialProps.uniforms.u_WobbleSpeed.value\n  })\n})\n\nconst { speed, amplitude, frequency } = useControls({\n  speed: {\n    value: materialProps.uniforms.u_WobbleSpeed.value,\n    min: 0,\n    max: 10,\n  },\n  amplitude: {\n    value: materialProps.uniforms.u_WobbleAmplitude.value,\n    min: 0,\n    max: 0.2,\n    step: 0.01,\n  },\n  frequency: {\n    value: materialProps.uniforms.u_WobbleFrequency.value,\n    min: 1,\n    max: 30,\n  },\n})\n\nwatch([speed.value, amplitude.value, frequency.value], () => {\n  materialProps.uniforms.u_WobbleSpeed.value = speed.value.value\n  materialProps.uniforms.u_WobbleAmplitude.value = amplitude.value.value\n  materialProps.uniforms.u_WobbleFrequency.value = frequency.value.value\n})\n</script>\n\n<template>\n  <TresLeches />\n  <TresCanvas v-bind=\"gl\">\n    <TresPerspectiveCamera\n      :position=\"[0, 2, 4]\"\n      :look-at=\"[0, 0, 0]\"\n    />\n\n    <OrbitControls />\n\n    <TresMesh>\n      <TresTorusKnotGeometry :args=\"[1, 0.3, 512, 32]\" />\n      <CustomShaderMaterial v-bind=\"materialProps\" />\n    </TresMesh>\n\n    <Suspense>\n      <StatsGl />\n    </Suspense>\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/materials/GlassMaterialDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { Box, MeshGlassMaterial, OrbitControls, Sphere } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { BasicShadowMap, NoToneMapping, SRGBColorSpace } from 'three'\nimport { ref, shallowRef, watch } from 'vue'\n\nconst gl = {\n  clearColor: '#82DBC5',\n  shadows: true,\n  alpha: false,\n  shadowMapType: BasicShadowMap,\n  outputColorSpace: SRGBColorSpace,\n  toneMapping: NoToneMapping,\n}\n\nconst context = ref()\nconst glassMaterialRef = shallowRef()\nconst boxRef = shallowRef()\n\nwatch(glassMaterialRef, (value) => {\n  boxRef.value.instance.material.dispose()\n  boxRef.value.instance.material = value.instance\n})\n</script>\n\n<template>\n  <TresCanvas\n    v-bind=\"gl\"\n    ref=\"context\"\n  >\n    <TresPerspectiveCamera :position=\"[3, 3, 3]\" />\n    <TresMesh :position-x=\"3\">\n      <TresTorusKnotGeometry :args=\"[1, 0.4, 256, 20]\" />\n      <MeshGlassMaterial ref=\"glassMaterialRef\" />\n    </TresMesh>\n    <Sphere :scale=\"0.5\">\n      <MeshGlassMaterial />\n    </Sphere>\n    <Box\n      ref=\"boxRef\"\n      :position-x=\"-3\"\n    />\n    <TresMesh :position=\"[0, 0, -1]\">\n      <TresPlaneGeometry :args=\"[3, 3]\" />\n      <TresMeshBasicMaterial :color=\"0xFF1111\" />\n    </TresMesh>\n    <TresGridHelper :args=\"[10, 10]\" />\n    <TresAmbientLight :intensity=\"1\" />\n    <TresDirectionalLight\n      :intensity=\"1\"\n      :position=\"[2, 2, 2]\"\n    />\n    <OrbitControls />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/materials/HolographicMaterialDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { HolographicMaterial, OrbitControls, Sphere } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { BasicShadowMap, NoToneMapping, SRGBColorSpace } from 'three'\nimport { shallowRef, watch } from 'vue'\n\nconst gl = {\n  clearColor: '#333',\n  shadows: true,\n  alpha: false,\n  shadowMapType: BasicShadowMap,\n  outputColorSpace: SRGBColorSpace,\n  toneMapping: NoToneMapping,\n}\nconst holographicMaterialRef = shallowRef()\n\nwatch(holographicMaterialRef, (value) => {\n  // eslint-disable-next-line no-console\n  console.log('jaime ~ watch ~ value:', value)\n})\n</script>\n\n<template>\n  <TresCanvas\n    v-bind=\"gl\"\n  >\n    <TresPerspectiveCamera :position=\"[3, 3, 3]\" />\n    <Sphere :scale=\"0.5\">\n      <HolographicMaterial\n        ref=\"holographicMaterialRef\"\n        :fresnel-amount=\"0.8\"\n        :enable-blinking=\"true\"\n        :blink-fresnel-only=\"true\"\n        :hologram-brightness=\"0.17\"\n      />\n      <!--\n        :fresnel-opacity=\"0.15\"\n        :scanline-size=\"6\"\n        :signal-speed=\"2.3\"\n        hologram-color=\"#ff0000\"\n        :hologram-opacity=\"1.\"\n        :enable-additive=\"true\"\n        :side=\"FrontSide\" -->\n    </Sphere>\n    <TresAmbientLight :intensity=\"1\" />\n    <TresDirectionalLight\n      :intensity=\"1\"\n      :position=\"[2, 2, 2]\"\n    />\n    <OrbitControls />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/materials/MeshDiscardMaterialDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { TresCanvas } from '@tresjs/core'\nimport { MeshDiscardMaterial } from '@tresjs/cientos'\n\nconst i = shallowRef(0)\n\nlet intervalId: string | number | NodeJS.Timeout | undefined\nonMounted(() => {\n  intervalId = setInterval(() => {\n    i.value++\n  }, 1000)\n})\n\nonUnmounted(() => {\n  clearInterval(intervalId)\n})\n</script>\n\n<template>\n  <TresCanvas clear-color=\"#333\">\n    <TresPerspectiveCamera :position=\"[0, 0, 5]\" />\n    <TresMesh>\n      <TresBoxGeometry />\n      <MeshDiscardMaterial v-if=\"i % 2\" />\n      <TresMeshNormalMaterial v-else />\n      <TresMesh :position-y=\"1\" :scale=\"0.33\">\n        <TresBoxGeometry />\n        <TresMeshNormalMaterial />\n      </TresMesh>\n    </TresMesh>\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/materials/MeshReflectionMaterialDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { MeshReflectionMaterial, OrbitControls, useTextures } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { TresLeches, useControls } from '@tresjs/leches'\nimport { shallowRef } from 'vue'\nimport '@tresjs/leches/styles'\n\nuseControls('fpsgraph')\nconst {\n  mix,\n  sharpMix,\n  sharpDepthScale,\n  sharpDepthBias,\n  sharpDepthEdgeMin,\n  sharpDepthEdgeMax,\n  blurMixSmooth,\n  blurMixRough,\n  blurDepthScale,\n  blurDepthBias,\n  blurDepthEdgeMin,\n  blurDepthEdgeMax,\n  blurWidth,\n  blurHeight,\n  distortion,\n  reflectorOffset,\n  roughness,\n  metalness,\n  useDiffuseMap,\n  useRoughnessMap,\n  useNormalMap,\n  useDistortionMap,\n} = useControls({\n  mix: { value: 1, min: 0, max: 1, step: 0.01 },\n\n  sharpMix: { value: 1, min: 0, max: 1, step: 0.01 },\n  sharpDepthScale: { value: 1.0, min: 0, max: 10, step: 0.1 },\n  sharpDepthBias: { label: 'shrp-bias', value: 0.0, min: 0.0, max: 1, step: 0.01 },\n  sharpDepthEdgeMin: { label: 'shrp-min', value: 0.0, min: 0.0, max: 1, step: 0.01 },\n  sharpDepthEdgeMax: { label: 'shrp-max', value: 0.2, min: 0.01, max: 1, step: 0.01 },\n\n  blurMixSmooth: { value: 1.0, min: 0, max: 1, step: 0.01 },\n  blurMixRough: { value: 0.0, min: 0, max: 1, step: 0.01 },\n  blurDepthScale: { value: 1, min: 0, max: 10, step: 0.1 },\n  blurDepthBias: { label: 'blur-bias', value: 0.0, min: 0.0, max: 1, step: 0.01 },\n  blurDepthEdgeMin: { label: 'blur-min', value: 0.0, min: 0.0, max: 1, step: 0.01 },\n  blurDepthEdgeMax: { label: 'blur-max', value: 0.2, min: 0.01, max: 1, step: 0.01 },\n  blurWidth: { value: 300, min: 0, max: 500, step: 1 },\n  blurHeight: { value: 100, min: 0, max: 500, step: 1 },\n\n  distortion: { value: 0.2, min: 0.01, max: 1, step: 0.01 },\n  reflectorOffset: { value: 0.0, min: -5, max: 5, step: 0.01 },\n\n  roughness: { value: 1.0, min: 0, max: 1, step: 0.01 },\n  metalness: { value: 0.0, min: 0.0, max: 1, step: 0.01 },\n\n  useDiffuseMap: true,\n  useRoughnessMap: true,\n  useNormalMap: true,\n  useDistortionMap: true,\n})\n\nconst PATH = 'https://raw.githubusercontent.com/Tresjs/assets/d15ced5cf09eddb2dae680dbe993613daae9cea4/textures/rock/'\nconst { textures } = useTextures(['roughness.jpg', 'normal.jpg', 'displacement.png', 'diffuse.jpg'].map(p => PATH + p))\nconst [roughnessMap, normalMap, distortionMap, diffuseMap] = textures.value\n\nconst lightX = shallowRef(0)\nconst lightZ = shallowRef(0)\nconst rotationY = shallowRef(0)\n</script>\n\n<template>\n  <TresLeches />\n  <TresCanvas clear-color=\"#050505\">\n    <TresPerspectiveCamera\n      :position=\"[2, 5, 5]\"\n      :fov=\"70\"\n      :look-at=\"[0, 0, 0]\"\n      :dpr=\"[1, 1.5]\"\n    />\n    <OrbitControls />\n\n    <TresFog\n      attach=\"fog\"\n      :args=\"['#191920', 10, 35]\"\n    />\n    <TresPointLight\n      :intensity=\"20\"\n      :position=\"[lightX, 2, lightZ]\"\n    />\n\n    <TresGroup :rotation-y=\"rotationY\">\n      <TresMesh :position=\"[0, 1.5, 0]\">\n        <TresTorusGeometry />\n        <TresMeshNormalMaterial color=\"red\" />\n      </TresMesh>\n\n      <TresMesh :position=\"[-2, 1.0, 1]\">\n        <TresBoxGeometry />\n        <TresMeshStandardMaterial color=\"blue\" />\n      </TresMesh>\n      <TresMesh\n        :position=\"[2, 1.0, 1]\"\n        :scale=\"0.5\"\n      >\n        <TresTorusKnotGeometry />\n        <TresMeshStandardMaterial color=\"green\" />\n      </TresMesh>\n    </TresGroup>\n\n    <TresMesh :rotation=\"[-Math.PI / 2, 0, 0]\">\n      <TresPlaneGeometry :args=\"[10, 10]\" />\n      <MeshReflectionMaterial\n        :resolution=\"512\"\n        :mix=\"mix.value\"\n\n        :blur-mix-smooth=\"blurMixSmooth.value\"\n        :blur-mix-rough=\"blurMixRough.value\"\n        :blur-depth-edge-min=\"blurDepthEdgeMin.value\"\n        :blur-depth-edge-max=\"blurDepthEdgeMax.value\"\n        :blur-depth-bias=\"blurDepthBias.value\"\n        :blur-depth-scale=\"blurDepthScale.value\"\n        :blur-size=\"[blurWidth.value, blurHeight.value]\"\n\n        :sharp-mix=\"sharpMix.value\"\n        :sharp-depth-edge-min=\"sharpDepthEdgeMin.value\"\n        :sharp-depth-edge-max=\"sharpDepthEdgeMax.value\"\n        :sharp-depth-scale=\"sharpDepthScale.value\"\n        :sharp-depth-bias=\"sharpDepthBias.value\"\n\n        :distortion=\"distortion.value\"\n        :reflector-offset=\"reflectorOffset.value\"\n\n        :roughness=\"roughness.value\"\n        :metalness=\"metalness.value\"\n        :map=\"useDiffuseMap.value ? diffuseMap : undefined\"\n        :normal-map=\"useNormalMap.value ? normalMap : undefined\"\n        :distortion-map=\"useDistortionMap.value ? distortionMap : undefined\"\n        :roughness-map=\"useRoughnessMap.value ? roughnessMap : undefined\"\n      />\n    </TresMesh>\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/materials/PointMaterialDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { MathUtils, NoToneMapping } from 'three'\nimport { TresCanvas } from '@tresjs/core'\nimport { OrbitControls, PointMaterial } from '@tresjs/cientos'\nimport { TresLeches, useControls } from '@tresjs/leches'\nimport '@tresjs/leches/styles'\n\nconst positions = new Float32Array(Array.from({ length: 1000 }, () => [\n  MathUtils.randFloatSpread(8),\n  MathUtils.randFloatSpread(8),\n  MathUtils.randFloatSpread(8),\n]).flat())\n\nconst c = useControls({\n  color: false,\n  depthTest: false,\n  enabled: true,\n  size: { value: 10, min: 0.1, max: 20, step: 0.1 },\n  sizeAttenuation: false,\n  toneMapped: false,\n  transparent: true,\n})\n</script>\n\n<template>\n  <TresLeches />\n  <TresCanvas :tone-mapping=\"NoToneMapping\" clear-color=\"#222\" :raycaster=\"{ params: { Points: { threshold: 0.2 } } }\">\n    <TresPerspectiveCamera :position=\"[10, 10, 10]\" />\n    <OrbitControls />\n    <TresPoints :limit=\"positions.length\">\n      <PointMaterial\n        v-if=\"c.enabled.value.value\"\n        :color=\"c.color.value.value ? '#F00' : '#FFF'\"\n        :size=\"c.size.value.value\"\n        :size-attenuation=\"c.sizeAttenuation.value.value\"\n        :transparent=\"c.transparent.value.value\"\n        :depth-test=\"c.depthTest.value.value\"\n        :tone-mapped=\"c.toneMapped.value.value\"\n      />\n      <TresBufferGeometry>\n        <TresBufferAttribute :args=\"[positions, 3]\" attach=\"attributes-position\" />\n      </TresBufferGeometry>\n    </TresPoints>\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/materials/WobbleMaterialDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { MeshWobbleMaterial, OrbitControls } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { BasicShadowMap, NoToneMapping, SRGBColorSpace } from 'three'\nimport { ref } from 'vue'\n\nconst gl = {\n  clearColor: '#82DBC5',\n  shadows: true,\n  alpha: false,\n  shadowMapType: BasicShadowMap,\n  outputColorSpace: SRGBColorSpace,\n  toneMapping: NoToneMapping,\n}\n\nconst context = ref()\n</script>\n\n<template>\n  <TresCanvas\n    v-bind=\"gl\"\n    ref=\"context\"\n    render-mode=\"on-demand\"\n  >\n    <TresPerspectiveCamera :position=\"[3, 3, 3]\" />\n    <TresMesh>\n      <TresTorusGeometry />\n      <MeshWobbleMaterial\n        color=\"orange\"\n        :speed=\"10\"\n        :factor=\"8\"\n      />\n    </TresMesh>\n    <TresGridHelper :args=\"[10, 10]\" />\n    <TresAmbientLight :intensity=\"1\" />\n    <TresDirectionalLight\n      :intensity=\"1\"\n      :position=\"[2, 2, 2]\"\n    />\n    <OrbitControls />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/misc/BakeShadowsDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { BakeShadows, CameraControls } from '@tresjs/cientos'\nimport { TresCanvas, useRenderLoop, vLightHelper } from '@tresjs/core'\nimport { Color, NoToneMapping, SRGBColorSpace } from 'three'\nimport { shallowRef } from 'vue'\n\nconst gl = {\n  clearColor: '#82DBC5',\n  outputColorSpace: SRGBColorSpace,\n  toneMapping: NoToneMapping,\n  shadows: true,\n}\n\nconst cubeRef = shallowRef()\n\nconst { onLoop } = useRenderLoop()\n\nonLoop(({ elapsed }) => {\n  if (cubeRef.value) {\n    cubeRef.value.rotation.y = elapsed * 0.5\n    cubeRef.value.rotation.x = elapsed * 0.5\n  }\n})\n</script>\n\n<template>\n  <TresCanvas\n    v-bind=\"gl\"\n  >\n    <TresPerspectiveCamera :position=\"[0, 2, 5]\" />\n    <CameraControls />\n    <BakeShadows />\n    <TresMesh\n      ref=\"cubeRef\"\n      cast-shadow\n    >\n      <TresBoxGeometry />\n      <TresMeshStandardMaterial :color=\"new Color(0x00FF00)\" />\n    </TresMesh>\n    <TresMesh\n      receive-shadow\n      :position=\"[0, -2, 0]\"\n      :rotation-x=\"-Math.PI / 2\"\n    >\n      <TresPlaneGeometry :args=\"[5, 5]\" />\n      <TresMeshStandardMaterial :color=\"new Color(0xF7F7F7)\" />\n    </TresMesh>\n    <TresDirectionalLight\n      v-light-helper\n      cast-shadow\n      :position=\"[0, 10, 0]\"\n    />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/misc/Card.vue",
    "content": "<script setup lang=\"ts\">\ndefineProps({\n  active: Boolean,\n})\n\nonMounted(() => {\n  // eslint-disable-next-line no-console\n  console.log('card mounted')\n})\n</script>\n\n<template>\n  <div\n    class=\" shadow-lg transition-all duration-1000 p-2 rounded-lg\"\n    :class=\"active ? 'bg-light' : 'bg-dark'\"\n  >\n    I'm a card {{ active ? '📦' : '📭' }}\n  </div>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/misc/GLTFExporterDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { CameraControls, useGLTFExporter } from '@tresjs/cientos'\nimport { TresCanvas, useRenderLoop } from '@tresjs/core'\nimport { MeshStandardMaterial, TorusGeometry } from 'three'\nimport { shallowRef } from 'vue'\n\nconst donutMaterial = new MeshStandardMaterial({})\nconst donutGeometry = new TorusGeometry(1, 0.5, 16, 32)\nconst boxRef = shallowRef()\n\nconst downloadScene = () => useGLTFExporter(boxRef.value.parent)\nconst downloadCube = () => useGLTFExporter(boxRef.value, { fileName: 'cube', binary: true })\n\nconst { onLoop } = useRenderLoop()\nonLoop(({ elapsed }) => {\n  if (boxRef.value) {\n    boxRef.value.rotation.x = elapsed\n    boxRef.value.rotation.y = elapsed\n  }\n})\n</script>\n\n<template>\n  <div>\n    <div class=\"downloads-buttons\">\n      <button @click=\"downloadScene\">\n        Download Scene\n      </button>\n      <button @click=\"downloadCube\">\n        Download Cube\n      </button>\n    </div>\n    <TresCanvas\n      clear-color=\"#82DBC5\"\n      window-size\n    >\n      <TresPerspectiveCamera :position=\"[0, 2, 5]\" />\n      <TresMesh\n        v-for=\"i in 20\"\n        :key=\"i\"\n        :geometry=\"donutGeometry\"\n        :material=\"donutMaterial\"\n        :position=\"[0.5 + (i * (Math.random() - 0.5) * 5),\n                    0.5 + (i * (Math.random() - 0.5) * 5),\n                    0.5 + (i * (Math.random() - 0.5) * 5)]\"\n        :scale=\"(i * 0.5) + 1\"\n      />\n      <TresMesh\n        ref=\"boxRef\"\n        :position-z=\"30\"\n        :scale=\"10\"\n      >\n        <TresBoxGeometry :args=\"[1, 1, 1]\" />\n        <TresMeshStandardMaterial :color=\"0x00FF00\" />\n      </TresMesh>\n      <CameraControls :distance=\"75\" />\n      <TresDirectionalLight :position=\"[0, 10, 10]\" />\n    </TresCanvas>\n  </div>\n</template>\n\n<style scoped>\n.downloads-buttons {\n  position: absolute;\n  top: 0;\n  left: 0;\n  z-index: 100;\n  display: flex;\n  justify-content: space-evenly;\n  width: 100%;\n}\n</style>\n"
  },
  {
    "path": "playground/vue/src/pages/misc/HTMLDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { Html, OrbitControls } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { TresLeches, useControls } from '@tresjs/leches'\nimport { reactive, ref } from 'vue'\nimport Card from './Card.vue'\nimport '@tresjs/leches/styles'\n\nconst sphereRef = ref(null)\nconst torusRef = ref(null)\n\nconst state = reactive({\n  wrapperClass: 'wrapper',\n  as: 'div',\n  center: true,\n})\n\nconst isActive = ref(false)\nconst { showHtml } = useControls({\n  showHtml: false,\n})\n</script>\n\n<template>\n  <TresLeches />\n  <TresCanvas clear-color=\"#82DBC5\" shadows>\n    <TresPerspectiveCamera :position=\"[3, 0, 8]\" />\n    <OrbitControls />\n    <TresMesh\n      :position=\"[1, 1, 1]\"\n      @click=\"isActive = !isActive\"\n    >\n      <TresBoxGeometry />\n      <TresMeshNormalMaterial />\n      <Html\n        v-if=\"showHtml\"\n        v-bind=\"state\"\n        transform\n        :occlude=\"[sphereRef]\"\n      >\n        <h1\n          class=\"text-xs p-0.5 rounded\"\n          :class=\"isActive ? 'bg-dark' : 'bg-white'\"\n        >\n          Box\n        </h1>\n      </Html>\n    </TresMesh>\n    <TresMesh\n      ref=\"sphereRef\"\n      :position=\"[4, 1, 1]\"\n    >\n      <TresSphereGeometry />\n      <TresMeshNormalMaterial />\n      <Html\n        v-bind=\"state\"\n        transform\n        :position=\"[0.5, 1, 0]\"\n      >\n        <Card :active=\"isActive\" />\n      </Html>\n    </TresMesh>\n    <TresMesh\n      ref=\"torusRef\"\n      :position=\"[7, 1, 1]\"\n    >\n      <Html :position=\"[0.5, 1, 0]\">\n        <Card :active=\"isActive\" />\n      </Html>\n      <TresTorusGeometry />\n      <TresMeshNormalMaterial />\n    </TresMesh>\n    <TresAmbientLight :intensity=\"1\" />\n  </TresCanvas>\n</template>\n\n<style scoped>\n.web {\n  width: 600px;\n  height: 400px;\n  border-radius: 10px;\n}\n</style>\n"
  },
  {
    "path": "playground/vue/src/pages/misc/LODDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { LOD } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { BoxGeometry, IcosahedronGeometry, MeshBasicMaterial, Vector3 } from 'three'\n\nconst COUNT = 1000\nconst positions = Array.from({ length: COUNT }).fill(0).map(() => {\n  return new Vector3(\n    10000 * (Math.random() * 2 - 1),\n    7500 * (Math.random() * 2 - 1),\n    10000 * (Math.random() * 2 - 1),\n  )\n})\n\nconst geometries = [\n  new IcosahedronGeometry(100, 16),\n  new IcosahedronGeometry(100, 8),\n  new IcosahedronGeometry(100, 4),\n  new IcosahedronGeometry(100, 2),\n  new BoxGeometry(100, 100, 100),\n]\n\nconst materials = [\n  new MeshBasicMaterial({ color: 'red', wireframe: true }),\n  new MeshBasicMaterial({ color: 'orange', wireframe: true }),\n  new MeshBasicMaterial({ color: 'yellow', wireframe: true }),\n  new MeshBasicMaterial({ color: 'green', wireframe: true }),\n  new MeshBasicMaterial({ color: 'blue', wireframe: true }),\n]\n\nconst x = ref(0)\nlet intervalId: ReturnType<typeof setInterval>\nlet elapsed = 0\n\nconst levels = ref([1000, 2000, 3000, 4000, 5000])\n\nonMounted(() => {\n  intervalId = setInterval(() => {\n    elapsed += 0.01\n    x.value = Math.cos(elapsed) * 5000\n  })\n})\n\nfunction resetLevels() {\n  const i = Math.random() * 10000\n  levels.value = [i, i * 2, i * 3, i * 4, i * 5]\n\n  // NOTE: Make `levels` too short sometimes.\n  if (Math.random() > 0.5) {\n    while (levels.value.length && Math.random() > 0.5) {\n      levels.value.pop()\n    }\n  }\n  else {\n    // NOTE: Reverse levels sometimes.\n    levels.value.reverse()\n  }\n}\n\nonUnmounted(() => {\n  clearInterval(intervalId)\n})\n</script>\n\n<template>\n  <TresCanvas clear-color=\"gray\" @pointerdown=\"resetLevels\">\n    <TresPerspectiveCamera :near=\"1\" :far=\"25000\" :position=\"[0, 0, 0]\" />\n    <TresGroup :position-z=\"x\">\n      <LOD v-for=\"position, i of positions\" :key=\"i\" :levels=\"levels\" :position=\"position\">\n        <TresMesh :geometry=\"geometries[0]\" :material=\"materials[0]\" />\n        <TresMesh :geometry=\"geometries[1]\" :material=\"materials[1]\" />\n        <TresMesh :geometry=\"geometries[2]\" :material=\"materials[2]\" />\n        <TresMesh :geometry=\"geometries[3]\" :material=\"materials[3]\" />\n        <TresMesh :geometry=\"geometries[4]\" :material=\"materials[4]\" />\n      </LOD>\n    </TresGroup>\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/misc/LaptopDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { ContactShadows, Html, Levioso, OrbitControls, useGLTF } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\n\nconst { nodes }\n  = useGLTF('https://vazxmixjsiawhamofees.supabase.co/storage/v1/object/public/models/macbook/model.gltf', { draco: true })\n\nconst laptop = computed(() => nodes.value.Macbook)\n</script>\n\n<template>\n  <TresCanvas clear-color=\"#241a1a\" shadows>\n    <TresPerspectiveCamera :position=\"[-5, 4, 3]\" />\n    <OrbitControls />\n    <Levioso>\n      <primitive v-if=\"laptop\" :object=\"laptop\">\n        <Html\n          transform\n          wrapper-class=\"webpage\"\n          :distance-factor=\"11\"\n          :position=\"[0, 10.5, -13.6]\"\n          occlude\n          :rotation-x=\"-0.256\"\n        >\n          <iframe\n            class=\"rounded-lg w-[1024px] h-[670px]\"\n            src=\"https://tresjs.org\"\n            frameborder=\"0\"\n          ></iframe>\n        </Html>\n      </primitive>\n    </Levioso>\n    <ContactShadows\n      :blur=\"3.5\"\n      :resolution=\"512\"\n      :opacity=\"1\"\n    />\n    <TresAmbientLight :intensity=\"1\" />\n    <TresDirectionalLight\n      :intensity=\"2\"\n      :position=\"[2, 3, 0]\"\n      :cast-shadow=\"true\"\n      :shadow-camera-far=\"50\"\n      :shadow-camera-left=\"-10\"\n      :shadow-camera-right=\"10\"\n      :shadow-camera-top=\"10\"\n      :shadow-camera-bottom=\"-10\"\n    />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/misc/StatsDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { CameraControls, Stats } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { NoToneMapping, SRGBColorSpace } from 'three'\nimport { shallowRef, watch } from 'vue'\nimport TestStars from '../../components/StarsForTest.vue'\n\nconst gl = {\n  clearColor: '#000',\n  outputColorSpace: SRGBColorSpace,\n  toneMapping: NoToneMapping,\n}\n\nconst statsGLRef = shallowRef()\n\nwatch(statsGLRef, (value) => {\n  // eslint-disable-next-line no-console\n  console.log('jaime ~ watch ~ value:', value.instance)\n})\n</script>\n\n<template>\n  <TresCanvas\n    v-bind=\"gl\"\n  >\n    <TresPerspectiveCamera :position=\"[0, 2, 5]\" />\n    <Stats ref=\"statsGLRef\" />\n    <TestStars />\n    <CameraControls :distance=\"500\" />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/misc/StatsGlDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { CameraControls, StatsGl } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { NoToneMapping, SRGBColorSpace } from 'three'\nimport { shallowRef, watch } from 'vue'\nimport TestStars from '../../components/StarsForTest.vue'\n\nconst gl = {\n  clearColor: '#000',\n  outputColorSpace: SRGBColorSpace,\n  toneMapping: NoToneMapping,\n}\n\nconst statsRef = shallowRef()\n\nwatch(statsRef, (value) => {\n  // eslint-disable-next-line no-console\n  console.log('jaime ~ watch ~ value:', value.instance)\n})\n</script>\n\n<template>\n  <TresCanvas\n    v-bind=\"gl\"\n  >\n    <TresPerspectiveCamera :position=\"[0, 2, 5]\" />\n    <StatsGl ref=\"statsRef\" />\n    <TestStars />\n    <CameraControls :distance=\"500\" />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/misc/useIntersect/TheExperience.vue",
    "content": "<script setup lang=\"ts\">\nimport { Torus, useIntersect } from '@tresjs/cientos'\n\nconst emit = defineEmits(['intersect'])\n\nconst { ref, intersect, off } = useIntersect()\n\nwatch(intersect, () => emit('intersect', intersect.value))\ndefineExpose({ off })\n</script>\n\n<template>\n  <Torus ref=\"ref\">\n    <TresMeshNormalMaterial />\n  </Torus>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/misc/useIntersect/index.vue",
    "content": "<script setup lang=\"ts\">\nimport { TresCanvas } from '@tresjs/core'\nimport TheExperience from './TheExperience.vue'\n\nconst r = shallowRef({ off: () => {} })\nconst txt = shallowRef('')\nconst ry = shallowRef(0)\n\nlet elapsed = 0\nlet intervalId: ReturnType<typeof setInterval>\n\nfunction update() {\n  elapsed += 1000 / 30\n  ry.value = elapsed * 0.001\n}\nonMounted(() => { intervalId = setInterval(update, 1000 / 30) })\nonUnmounted(() => clearInterval(intervalId))\n</script>\n\n<template>\n  <div class=\"overlay-info\">\n    <h1><code>useIntersect</code></h1>\n    <h2>Setup</h2>\n    <p>The camera rotates, sending a torus around the screen.</p>\n    <p>The torus' ref has been sent to <code>useIntersect</code>.</p>\n    <h2>Intersect status</h2>\n    <p>{{ txt }}</p>\n    <h2><code>off</code></h2>\n    <p>Hitting this button should stop <code>useIntersect</code> updates.</p>\n    <button @pointerdown=\"r.off()\">Off</button>\n  </div>\n  <TresCanvas clear-color=\"#333\">\n    <TresPerspectiveCamera :rotation-y=\"ry\" />\n    <TheExperience ref=\"r\" @intersect=\"(b) => txt = b\" />\n  </TresCanvas>\n</template>\n\n<style scoped>\n.overlay-info {\n  position: fixed;\n  top: 0;\n  left: 0;\n  margin: 10px;\n  padding: 16px;\n  max-width: 400px;\n  z-index: 1000;\n  font-family:\n    ui-sans-serif,\n    system-ui,\n    -apple-system,\n    BlinkMacSystemFont,\n    'Segoe UI',\n    Roboto,\n    'Helvetica Neue',\n    Arial,\n    'Noto Sans',\n    sans-serif,\n    'Apple Color Emoji',\n    'Segoe UI Emoji',\n    'Segoe UI Symbol',\n    'Noto Color Emoji';\n  font-size: small;\n  background-color: white;\n  border-radius: 6px;\n  overflow: auto;\n}\n</style>\n"
  },
  {
    "path": "playground/vue/src/pages/shapes/CatmullRomCurve3Demo.vue",
    "content": "<script setup lang=\"ts\">\nimport { CatmullRomCurve3, OrbitControls } from '@tresjs/cientos'\nimport { TresCanvas, useRenderLoop } from '@tresjs/core'\n\nconst NUM_POINTS = 10\nconst points = ref(Array.from({ length: NUM_POINTS }).fill(0).map((_, i) => [i * 0.1, 0, 0]))\nconst colors = ref([\n  [1.0, 0.0, 0.0],\n  [0.9, 0.1, 0.0],\n  [0.8, 0.2, 0.0],\n  [0.7, 0.3, 0.0],\n  [0.6, 0.4, 0.0],\n  [0.5, 0.5, 0.0],\n  [0.4, 0.6, 0.0],\n  [0.3, 0.7, 0.0],\n  [0.2, 0.8, 0.0],\n  [0.1, 0.9, 0.0],\n  [0.0, 1.0, 0.0],\n  [0.0, 0.9, 0.1],\n  [0.0, 0.8, 0.2],\n  [0.0, 0.7, 0.3],\n  [0.0, 0.6, 0.4],\n  [0.0, 0.5, 0.5],\n  [0.0, 0.4, 0.6],\n  [0.0, 0.3, 0.7],\n  [0.0, 0.2, 0.8],\n  [0.0, 0.1, 0.9],\n  [0.0, 0.0, 1.0],\n  [0.1, 0.0, 0.9],\n  [0.2, 0.0, 0.8],\n  [0.3, 0.0, 0.7],\n  [0.4, 0.0, 0.6],\n  [0.5, 0.0, 0.5],\n  [0.6, 0.0, 0.4],\n  [0.7, 0.0, 0.3],\n  [0.8, 0.0, 0.2],\n  [0.9, 0.0, 0.1],\n])\n\nconst lineWidth = ref(5)\nconst dashed = ref(true)\nconst dashSize = ref(1)\nconst dashScaleRef = ref(50)\nconst dashOffset = ref(0)\n\nuseRenderLoop().onLoop(({ elapsed }) => {\n  points.value.forEach((v, i) => {\n    const progress = i * 0.5 + elapsed * 0.25\n    v[0] = Math.cos(progress)\n    v[1] = Math.sin((progress) * Math.PI * 3) * 0.1\n    v[2] = Math.sin(progress)\n  })\n\n  const c = colors.value.pop()\n  colors.value.unshift(c)\n\n  dashed.value = Math.sin(elapsed * 0.5) < 0\n  dashSize.value = 2 * (Math.sin(elapsed) + 1)\n  dashScaleRef.value = 25 + 25 * Math.sin(elapsed)\n  dashOffset.value = 1 * (Math.sin(elapsed) + 1)\n\n  lineWidth.value = 0.1 * (Math.sin(elapsed) + 1) + 0.1\n})\n</script>\n\n<template>\n  <TresCanvas clear-color=\"#777\">\n    <CatmullRomCurve3\n      :position=\"[0, 0, 0]\"\n      :points=\"points\"\n      :vertex-colors=\"colors\"\n      :segments=\"100\"\n      :world-units=\"true\"\n      :line-width=\"lineWidth\"\n      :dashed=\"dashed\"\n      :dash-scale=\"dashScaleRef\"\n    />\n    <TresGridHelper />\n    <OrbitControls />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/shapes/CubicBezierLineDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { CubicBezierLine, OrbitControls } from '@tresjs/cientos'\nimport { TresCanvas, useRenderLoop } from '@tresjs/core'\nimport { TresLeches, useControls } from '@tresjs/leches'\nimport '@tresjs/leches/styles'\nimport { Vector3 } from 'three'\n\nconst c = useControls({\n  startX: { value: 0, min: -10, max: 10 },\n  startY: { value: 0, min: -10, max: 10 },\n  startZ: { value: 0, min: -10, max: 10 },\n  endX: { value: 3, min: -10, max: 10 },\n  endY: { value: 3, min: -10, max: 10 },\n  endZ: { value: 3, min: -10, max: 10 },\n  moveMidA: true,\n  moveMidB: true,\n  lineWidth: { value: 1, min: 0.01, max: 10 },\n  enabled: true,\n})\n\nconst midA = reactive([1, 1, 1] as [number, number, number])\nconst midB = new Vector3(2, 2, 2)\nconst colors = ref([\n  [1.0, 0.0, 0.0],\n  [0.9, 0.1, 0.0],\n  [0.8, 0.2, 0.0],\n  [0.7, 0.3, 0.0],\n  [0.6, 0.4, 0.0],\n  [0.5, 0.5, 0.0],\n  [0.4, 0.6, 0.0],\n  [0.3, 0.7, 0.0],\n  [0.2, 0.8, 0.0],\n  [0.1, 0.9, 0.0],\n  [0.0, 1.0, 0.0],\n  [0.0, 0.9, 0.1],\n  [0.0, 0.8, 0.2],\n  [0.0, 0.7, 0.3],\n  [0.0, 0.6, 0.4],\n  [0.0, 0.5, 0.5],\n  [0.0, 0.4, 0.6],\n  [0.0, 0.3, 0.7],\n  [0.0, 0.2, 0.8],\n  [0.0, 0.1, 0.9],\n  [0.0, 0.0, 1.0],\n  [0.1, 0.0, 0.9],\n  [0.2, 0.0, 0.8],\n  [0.3, 0.0, 0.7],\n  [0.4, 0.0, 0.6],\n  [0.5, 0.0, 0.5],\n  [0.6, 0.0, 0.4],\n  [0.7, 0.0, 0.3],\n  [0.8, 0.0, 0.2],\n  [0.9, 0.0, 0.1],\n])\n\nconst dashed = ref(true)\nconst dashScale = ref(50)\n\nuseRenderLoop().onLoop(({ elapsed }) => {\n  const lastColor = colors.value.pop()!\n  colors.value.unshift(lastColor)\n\n  dashed.value = Math.sin(elapsed * 0.5) < 0\n  dashScale.value = 5 + 5 * Math.sin(elapsed)\n\n  if (c.moveMidA.value.value) {\n    midA[1] = Math.sin(elapsed) * 4\n  }\n  if (c.moveMidB.value.value) {\n    midB.x = Math.cos(elapsed) * 4\n  }\n})\n</script>\n\n<template>\n  <TresLeches />\n  <TresCanvas clear-color=\"#777\">\n    <CubicBezierLine\n      v-if=\"c.enabled.value.value\"\n      :start=\"[c.startX.value.value, c.startY.value.value, c.startZ.value.value]\"\n      :end=\"[c.endX.value.value, c.endY.value.value, c.endZ.value.value]\"\n      :midA=\"midA\"\n      :midB=\"midB\"\n      :vertex-colors=\"colors\"\n      :world-units=\"true\"\n      :line-width=\"c.lineWidth.value.value\"\n      :dashed=\"dashed\"\n      :dash-scale=\"dashScale\"\n    />\n    <TresGridHelper />\n    <OrbitControls />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/shapes/Cylinder.vue",
    "content": "<script setup>\nimport { Cylinder, OrbitControls } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\n\nconst { random: r, floor: fl, PI } = Math\nconst choice = (arr) => {\n  return arr[fl(r() * arr.length)]\n}\nconst COLORS = [0x81DBC5, 0xEFAC35, 0xFFFFFF, 0x444444]\nconst colorsArgs = Array.from({ length: 9 }).fill({}).map(() =>\n  [choice(COLORS), [r() * 0.5, r() * 0.5, r(), fl(r() * 20) + 4, fl(r() * 10) + 4, false, 0, 2 * PI]],\n)\n</script>\n\n<template>\n  <TresCanvas\n    window-size\n    clear-color=\"#111\"\n  >\n    <TresPerspectiveCamera\n      :position=\"[0, 0, 7]\"\n      :fov=\"45\"\n      :aspect=\"1\"\n      :near=\"0.1\"\n      :far=\"1000\"\n    />\n    <OrbitControls />\n    <Cylinder\n      v-for=\"[color, args], i of colorsArgs\"\n      :key=\"i\"\n      :args=\"args\"\n      :position=\"[i % 3 - 1, Math.floor(i / 3) - 1, 0]\"\n    >\n      <TresMeshStandardMaterial\n        :color=\"color\"\n      />\n    </Cylinder>\n    <TresDirectionalLight\n      :position=\"[0, 2, 4]\"\n      :intensity=\"2\"\n    />\n    <TresAmbientLight />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/shapes/Line2Demo.vue",
    "content": "<script setup lang=\"ts\">\nimport { Line2, OrbitControls } from '@tresjs/cientos'\nimport { TresCanvas, useRenderLoop } from '@tresjs/core'\n\nconst NUM_POINTS = 10\nconst points = ref(Array.from({ length: NUM_POINTS }).fill(0).map((_, i) => [i * 0.1, 0, 0]))\nconst colors = ref([\n  [1.0, 0.0, 0.0],\n  [0.9, 0.1, 0.0],\n  [0.8, 0.2, 0.0],\n  [0.7, 0.3, 0.0],\n  [0.6, 0.4, 0.0],\n  [0.5, 0.5, 0.0],\n  [0.4, 0.6, 0.0],\n  [0.3, 0.7, 0.0],\n  [0.2, 0.8, 0.0],\n  [0.1, 0.9, 0.0],\n  [0.0, 1.0, 0.0],\n  [0.0, 0.9, 0.1],\n  [0.0, 0.8, 0.2],\n  [0.0, 0.7, 0.3],\n  [0.0, 0.6, 0.4],\n  [0.0, 0.5, 0.5],\n  [0.0, 0.4, 0.6],\n  [0.0, 0.3, 0.7],\n  [0.0, 0.2, 0.8],\n  [0.0, 0.1, 0.9],\n  [0.0, 0.0, 1.0],\n  [0.1, 0.0, 0.9],\n  [0.2, 0.0, 0.8],\n  [0.3, 0.0, 0.7],\n  [0.4, 0.0, 0.6],\n  [0.5, 0.0, 0.5],\n  [0.6, 0.0, 0.4],\n  [0.7, 0.0, 0.3],\n  [0.8, 0.0, 0.2],\n  [0.9, 0.0, 0.1],\n])\n\nconst lineWidth = ref(5)\nconst dashed = ref(true)\nconst dashScale = ref(50)\n\nuseRenderLoop().onLoop(({ elapsed }) => {\n  points.value.forEach((v, i) => {\n    const progress = i * 0.5 + elapsed * 0.25\n    v[0] = Math.cos(progress)\n    v[1] = Math.sin((progress) * Math.PI * 3) * 0.1\n    v[2] = Math.sin(progress)\n  })\n\n  const c = colors.value.pop()\n  colors.value.unshift(c)\n\n  dashed.value = Math.sin(elapsed * 0.5) < 0\n  dashScale.value = 5 + 5 * Math.sin(elapsed)\n  lineWidth.value = 0.1 * (Math.sin(elapsed) + 1) + 0.1\n})\n</script>\n\n<template>\n  <TresCanvas clear-color=\"#777\">\n    <Line2\n      :points=\"points\"\n      :vertex-colors=\"colors\"\n      :world-units=\"true\"\n      :line-width=\"lineWidth\"\n      :dashed=\"dashed\"\n      :dash-scale=\"dashScale\"\n    />\n    <TresGridHelper />\n    <OrbitControls />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/shapes/OnDemandShapesDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { Box, CatmullRomCurve3, Circle, Cone, Cylinder, Dodecahedron, Icosahedron, Octahedron, OrbitControls, Plane, Ring, RoundedBox, Sphere, Superformula, Tetrahedron, Torus, TorusKnot, Tube } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { QuadraticBezierCurve3, Vector3 } from 'three'\nimport { onUnmounted } from 'vue'\nimport OverlayInfo from '../../components/OverlayInfo.vue'\n\nconst COLORS = [0x81DBC5, 0xEFAC35, 0xFFFFFF, 0x444444]\nconst WIGGLE_SIZE = 0.3\nconst NUM_SHAPES = 17\n\nconst i = shallowRef(0)\nconst colorRef = shallowRef(COLORS[0])\nconst wiggle0 = shallowRef(0)\nconst wiggle1 = shallowRef(0)\nconst wiggle2 = shallowRef(0)\nconst wiggle3 = shallowRef(0)\nconst colorSkip = shallowRef(0)\nconst wiggles = [wiggle0, wiggle1, wiggle2, wiggle3, colorSkip]\n\nlet n = 0\nlet wiggle = wiggles[0]\nconst intervalId = setInterval(() => {\n  n += 0.2\n\n  if (n > Math.PI) {\n    n = 0\n    const oldWiggle = wiggle\n    wiggle = getArrayNext(wiggles, wiggle)\n    if (oldWiggle !== wiggle) { oldWiggle.value = 0 }\n    if (oldWiggle === wiggles[wiggles.length - 1] && wiggle === wiggles[0]) {\n      i.value = (i.value + 1) % NUM_SHAPES\n    }\n  }\n\n  wiggle.value = Math.sin(n) * WIGGLE_SIZE\n  if (wiggles.indexOf(wiggle) === wiggles.length - 1) {\n    colorRef.value = COLORS[Math.floor(Math.random() * COLORS.length)]\n  }\n}, 1000 / 60)\n\nfunction getArrayNext<T>(arr: T[], currVal: T) {\n  const i = arr.indexOf(currVal)\n  return arr[(i + 1) % arr.length]\n}\n\nonUnmounted(() => clearInterval(intervalId))\n</script>\n\n<template>\n  <TresCanvas\n    window-size\n    clear-color=\"#111\"\n    render-mode=\"on-demand\"\n  >\n    <TresPerspectiveCamera\n      :fov=\"45\"\n      :aspect=\"1\"\n      :near=\"0.1\"\n      :far=\"1000\"\n    />\n    <OrbitControls />\n    <Box\n      v-if=\"i === 0\"\n      :color=\"colorRef\"\n      :args=\"[1 + wiggle0, 1 + wiggle1, 1 + wiggle2 + wiggle3]\"\n    />\n    <CatmullRomCurve3\n      v-if=\"i === 1\"\n      :vertexColors=\"[colorRef, colorRef]\"\n      :points=\"[[-0.5 + wiggle0, -0.5 + wiggle1, -0.5], [0.5 + wiggle2, 0.5, 0.5]]\"\n      :line-width=\"40 + wiggle3 * 200\"\n    />\n    <Circle\n      v-if=\"i === 2\"\n      :color=\"colorRef\"\n      :args=\"[1 + wiggle0, 6 + Math.floor(wiggle1 * 100), wiggle2 * 5, 2 * Math.PI - wiggle3 * 5]\"\n    />\n    <Cone\n      v-if=\"i === 3\"\n      :color=\"colorRef\"\n      :args=\"[1 + wiggle0, 1 + wiggle1, 12 + Math.floor(wiggle2 * 100), 12, false, 0, Math.PI * 2 + wiggle3 * 10]\"\n    />\n    <Cylinder\n      v-if=\"i === 4\"\n      :color=\"colorRef\"\n      :args=\"[0.5 + wiggle0, 0.5 + wiggle1, 1 + wiggle2, 12 + Math.floor(wiggle3 * 100)]\"\n    />\n    <Dodecahedron\n      v-if=\"i === 5\"\n      :color=\"colorRef\"\n      :args=\"[0.5 + wiggle0 + wiggle1, Math.floor((wiggle2 + wiggle3) * 20)]\"\n    />\n    <Icosahedron\n      v-if=\"i === 6\"\n      :color=\"colorRef\"\n      :args=\"[0.5 + wiggle0 + wiggle1, Math.floor((wiggle2 + wiggle3) * 20)]\"\n    />\n    <Octahedron\n      v-if=\"i === 7\"\n      :color=\"colorRef\"\n      :args=\"[0.5 + wiggle0 + wiggle1, Math.floor((wiggle2 + wiggle3) * 20)]\"\n    />\n    <Plane\n      v-if=\"i === 8\"\n      :rotation-y=\"Math.PI * 0.5\"\n      :color=\"colorRef\"\n      :args=\"[1 + wiggle0 + wiggle1, 1 + wiggle2 + wiggle3]\"\n    />\n    <Ring\n      v-if=\"i === 9\"\n      :color=\"colorRef\"\n      :args=\"[0.5 + wiggle0, 1 + wiggle1, 16, 16, wiggle2 * 10, Math.PI * 2 - wiggle3 * 20]\"\n    />\n    <RoundedBox\n      v-if=\"i === 10\"\n      :color=\"colorRef\"\n      :args=\"[1 + wiggle0, 1 + wiggle1, 1 + wiggle2, 8, 0.2 + wiggle3]\"\n    />\n    <Sphere\n      v-if=\"i === 11\"\n      :color=\"colorRef\"\n      :args=\"[1 + wiggle0 + wiggle1, 32, 32, wiggle2 * 20, Math.PI * 2 - wiggle3 * 20]\"\n    />\n    <Superformula\n      v-if=\"i === 12\"\n      :color=\"colorRef\"\n      :widthSegments=\"124\"\n      :heightSegments=\"124\"\n      :numArmsA=\"12 + 100 * wiggle0\"\n      :numArmsB=\"12 + 100 * wiggle1\"\n      :expA=\"[30, 16 + 100 * wiggle2, 1.9]\"\n      :expB=\"[10, 16 + 100 * wiggle3, 1.9]\"\n    />\n    <Tetrahedron\n      v-if=\"i === 13\"\n      :color=\"colorRef\"\n      :args=\"[1 + 2 * (wiggle0 + wiggle1), 1 + Math.floor(200 * (wiggle2 + wiggle3))]\"\n    />\n    <Torus\n      v-if=\"i === 14\"\n      :color=\"colorRef\"\n      :args=\"[0.5 + wiggle0, 0.25 + wiggle1, 32 + Math.floor(100 * wiggle2), 32, 2 * Math.PI - 20 * wiggle3]\"\n    />\n    <TorusKnot\n      v-if=\"i === 15\"\n      :color=\"colorRef\"\n      :args=\"[0.5 + wiggle0, 0.1 + wiggle1, 256 + Math.floor(100 * wiggle2), 8 - Math.floor(20 * wiggle3)]\"\n    />\n    <Tube\n      v-if=\"i === 16\"\n      :color=\"colorRef\"\n      :args=\"[new QuadraticBezierCurve3(new Vector3(-1, 0, 0), new Vector3(0, 1, 0), new Vector3(1, 0, 0)), 20 + Math.floor(100 * wiggle0), 0.2 + 10 * (wiggle1 + wiggle2), 8 + Math.floor(50 * wiggle3)]\"\n    />\n  </TresCanvas>\n  <OverlayInfo>\n    <h1>render-mode=\"on-demand\" Shapes</h1>\n    <h2>Setup</h2>\n    <p>The canvas' \"render-mode\" is set to \"on-demand\". This means it only rerenders when <code>invalidate()</code> is called.</p>\n    <p>There should be 1 shape on the canvas at a time.</p>\n    <p>The shape should constantly be visibly changing properties. A pause indicates that a shape is not calling <code>invalidate()</code>.</p>\n  </OverlayInfo>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/shapes/QuadraticBezierLineDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { OrbitControls, QuadraticBezierLine } from '@tresjs/cientos'\nimport { TresCanvas, useRenderLoop } from '@tresjs/core'\nimport { TresLeches, useControls } from '@tresjs/leches'\nimport '@tresjs/leches/styles'\nimport { Vector3 } from 'three'\n\nconst c = useControls({\n  startX: { value: 0, min: -10, max: 10 },\n  startY: { value: 0, min: -10, max: 10 },\n  startZ: { value: 0, min: -10, max: 10 },\n  endX: { value: 3, min: -10, max: 10 },\n  endY: { value: 3, min: -10, max: 10 },\n  endZ: { value: -3, min: -10, max: 10 },\n  moveMid: true,\n  lineWidth: { value: 1, min: 0.01, max: 10 },\n  enabled: true,\n})\n\nconst mid = new Vector3(1, 1, 1)\nconst colors = ref([\n  [1.0, 0.0, 0.0],\n  [0.9, 0.1, 0.0],\n  [0.8, 0.2, 0.0],\n  [0.7, 0.3, 0.0],\n  [0.6, 0.4, 0.0],\n  [0.5, 0.5, 0.0],\n  [0.4, 0.6, 0.0],\n  [0.3, 0.7, 0.0],\n  [0.2, 0.8, 0.0],\n  [0.1, 0.9, 0.0],\n  [0.0, 1.0, 0.0],\n  [0.0, 0.9, 0.1],\n  [0.0, 0.8, 0.2],\n  [0.0, 0.7, 0.3],\n  [0.0, 0.6, 0.4],\n  [0.0, 0.5, 0.5],\n  [0.0, 0.4, 0.6],\n  [0.0, 0.3, 0.7],\n  [0.0, 0.2, 0.8],\n  [0.0, 0.1, 0.9],\n  [0.0, 0.0, 1.0],\n  [0.1, 0.0, 0.9],\n  [0.2, 0.0, 0.8],\n  [0.3, 0.0, 0.7],\n  [0.4, 0.0, 0.6],\n  [0.5, 0.0, 0.5],\n  [0.6, 0.0, 0.4],\n  [0.7, 0.0, 0.3],\n  [0.8, 0.0, 0.2],\n  [0.9, 0.0, 0.1],\n])\n\nconst dashed = ref(true)\nconst dashScale = ref(50)\n\nuseRenderLoop().onLoop(({ elapsed }) => {\n  const lastColor = colors.value.pop()!\n  colors.value.unshift(lastColor)\n\n  dashed.value = Math.sin(elapsed * 0.5) < 0\n  dashScale.value = 5 + 5 * Math.sin(elapsed)\n\n  if (c.moveMid.value.value) {\n    mid.y = Math.sin(elapsed) * 4\n  }\n})\n</script>\n\n<template>\n  <TresLeches />\n  <TresCanvas clear-color=\"#777\">\n    <TresPerspectiveCamera :position=\"[10, 10, 10]\" />\n    <OrbitControls />\n    <QuadraticBezierLine\n      v-if=\"c.enabled.value.value\"\n      :start=\"[c.startX.value.value, c.startY.value.value, c.startZ.value.value]\"\n      :end=\"[c.endX.value.value, c.endY.value.value, c.endZ.value.value]\"\n      :vertex-colors=\"colors\"\n      :world-units=\"true\"\n      :line-width=\"c.lineWidth.value.value\"\n      :dashed=\"dashed\"\n      :dash-scale=\"dashScale\"\n    />\n    <TresGridHelper />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/shapes/RoundedBoxDemo.vue",
    "content": "<script setup>\nimport { OrbitControls, RoundedBox } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { shallowRef, watch } from 'vue'\n\nconst boxRef = shallowRef()\n\nwatch(boxRef, (box) => {\n  // eslint-disable-next-line no-console\n  console.log(box)\n})\n</script>\n\n<template>\n  <TresCanvas\n    window-size\n    clear-color=\"#111\"\n  >\n    <TresPerspectiveCamera\n      :position=\"[0, 0, 7]\"\n      :fov=\"45\"\n      :aspect=\"1\"\n      :near=\"0.1\"\n      :far=\"1000\"\n    />\n    <OrbitControls />\n    <RoundedBox\n      ref=\"boxRef\"\n    >\n      <TresMeshBasicMaterial\n        :color=\"0x00FF00\"\n        wireframe\n      />\n    </RoundedBox>\n    <TresDirectionalLight\n      :position=\"[0, 2, 4]\"\n      :intensity=\"2\"\n    />\n    <TresAmbientLight />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/shapes/ScreenQuadDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { TresCanvas } from '@tresjs/core'\nimport { ScreenQuad } from '@tresjs/cientos'\nimport type { WebGLRenderer } from 'three'\nimport { RawShaderMaterial, RGBFormat, Vector2, WebGLRenderTarget } from 'three'\nimport OverlayInfo from '../../components/OverlayInfo.vue'\n\nconst vertexShader = `precision highp float;\nattribute vec2 position;\nvoid main() {\n  // Look ma! no projection matrix multiplication,\n  // because we pass the values directly in clip space coordinates.\n  gl_Position = vec4(position, 1.0, 1.0);\n}`\n\nconst fragmentShader = `precision highp float;\nuniform sampler2D uScene;\nuniform vec2 uResolution;\nvoid main() {\n  vec2 uv = gl_FragCoord.xy / uResolution.xy;\n  // Do your cool postprocessing here\n  gl_FragColor = vec4(step(0.5, uv.x), step(0.5, uv.y), 0.0, 1.0);\n}`\n\nconst resolution = new Vector2(100, 100)\n\nconst target = new WebGLRenderTarget(resolution.x, resolution.y, {\n  format: RGBFormat,\n  stencilBuffer: false,\n  depthBuffer: true,\n})\n\nconst mat = new RawShaderMaterial({\n  fragmentShader,\n  vertexShader,\n  uniforms: {\n    uScene: { value: target.texture },\n    uResolution: { value: resolution },\n  },\n})\n\nlet r: WebGLRenderer\nfunction onReady({ renderer }) {\n  r = renderer.instance\n  renderer.instance.getDrawingBufferSize(resolution)\n  target.setSize(resolution.x, resolution.y)\n  mat.uniforms.uResolution.value = resolution\n}\n\nconst imgData = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFQAAABUCAYAAAAcaxDBAAABN0lEQVR4Xu3buw2EMAAFQbsNQvpvijYu4JcTzkkOlgJW9vBSz+0c11j4O+bCh/s42gzU/rBArecINFAsgHMtNFAsgHMtNFAsgHMtNFAsgHMtNFAsgHMtNFAsgHMtNFAsgHMtNFAsgHMtNFAsgHMtNFAsgHMtNFAsgHMtNFAsgHMtNFAsgHMtNFAsgHMtNFAsgHMtNFAsgHMtNFAsgHMtNFAsgHMtVIM+vaXfKf12fOM/595nVYFC5EAh5psKNFAsgHMtNFAsgHMtNFAsgHMtNFAsgHMtNFAsgHMtNFAsgHMtNFAsgHMtNFAsgHMtNFAsgHMtNFAsgHMtNFAsgHMtNFAsgHMtNFAsgHMtNFAsgHMtNFAsgHMtNFAsgHMtNFAsgHMtNFAsgHMtNFAsgHMtNFAsgHMtFIPeNY3T4VOOUisAAAAASUVORK5CYII='\n\nlet intervalId: ReturnType<typeof setInterval>\nonMounted(() => {\n  intervalId = setInterval(() => {\n    if (r) {\n      // NOTE: Update material resolution to make it\n      // follow screen size changes.\n      r.getDrawingBufferSize(mat.uniforms.uResolution.value)\n    }\n  }, 1000 / 30)\n})\n\nonUnmounted(() => {\n  clearInterval(intervalId)\n  mat.dispose()\n  target.dispose()\n})\n</script>\n\n<template>\n  <OverlayInfo>\n    <h1>ScreenQuad</h1>\n    <p>This component is intended for creating (slightly faster) custom, full-screen post-processing.</p>\n    <h2>Setup</h2>\n    <p>In this scene, there is a <code>ScreenQuad</code>. The <code>ScreenQuad</code> has a custom material. The material's vertex shader places it \"in front of the camera\".</p>\n    <h2>Preview</h2>\n    <img :src=\"imgData\" />\n  </OverlayInfo>\n  <TresCanvas\n    window-size\n    clear-color=\"#111\"\n    @ready=\"onReady\"\n  >\n    <ScreenQuad>\n      <primitive :object=\"mat\" />\n    </ScreenQuad>\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/shapes/SuperformulaDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { OrbitControls, Superformula } from '@tresjs/cientos'\nimport { TresCanvas, useRenderLoop } from '@tresjs/core'\nimport { Color } from 'three'\n\nconst numArmsA = shallowRef(1)\nconst numArmsB = shallowRef(1)\nconst expA1 = shallowRef(1)\nconst expA2 = shallowRef(1)\nconst expA3 = shallowRef(1)\nconst expB1 = shallowRef(1)\nconst expB2 = shallowRef(1)\nconst expB3 = shallowRef(1)\n\nconst { sin, cos } = Math\n\nuseRenderLoop().onLoop(({ elapsed }) => {\n  const e = elapsed * 0.1\n  numArmsA.value = sin(e * Math.PI) * 24\n  expA1.value = (sin(e * Math.PI) + 2) * 30\n  expA2.value = (sin(e * Math.E) + 2) * 30\n  expA3.value = (sin(e * Math.SQRT2) + 2) * 30\n  numArmsB.value = cos(e) * 24\n  expB1.value = (cos(e * Math.PI) + 2) * 30\n  expB2.value = (cos(e * Math.E) + 2) * 30\n  expB3.value = (cos(e * Math.SQRT2) + 2) * 30\n})\n</script>\n\n<template>\n  <TresCanvas clear-color=\"#777\">\n    <TresDirectionalLight\n      :position=\"[3, 2, 1]\"\n      :intensity=\"8\"\n    />\n    <TresAmbientLight\n      :position=\"[3, 2, 1]\"\n      :intensity=\"1\"\n      :color=\"new Color('pink')\"\n    />\n    <Superformula\n      :width-segments=\"256\"\n      :height-segments=\"256\"\n      :num-arms-a=\"numArmsA\"\n      :exp-a=\"[expA1, expA2, expA3]\"\n      :num-arms-b=\"numArmsB\"\n      :exp-b=\"[expB1, expB2, expB3]\"\n    >\n      <TresMeshNormalMaterial />\n    </Superformula>\n    <TresGridHelper />\n    <OrbitControls />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/staging/AccumulativeShadowsDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { AccumulativeShadows, Box, Environment, Icosahedron, OrbitControls, Sphere } from '@tresjs/cientos'\nimport { NoToneMapping } from 'three'\nimport { TresCanvas } from '@tresjs/core'\nimport { TresLeches, useControls } from '@tresjs/leches'\nimport '@tresjs/leches/styles'\n\nconst c = useControls({\n  frames: { value: 100, min: 2, max: 200, step: 1 },\n  once: true,\n  accumulate: true,\n  limit: { value: 1000, min: 0, max: 10000, step: 10 },\n  isLimitInfinite: false,\n  blend: { value: 200, min: 2, max: 1000, step: 1 },\n  alphaTest: { value: 0.75, min: 0, max: 1, step: 0.01 },\n  colorBlend: { value: 2, min: 0, max: 5, step: 0.1 },\n  opacity: { value: 2, min: 0, max: 2, step: 0.1 },\n  resolution: { value: 2048, min: 16, max: 2048, step: 16 },\n  scale: { value: 12, min: 1, max: 24, step: 1 },\n  toneMapped: true,\n  isOrange: true,\n  enabled: true,\n})\n\nconst x = shallowRef(0)\n\nlet intervalId: ReturnType<typeof setInterval>\nlet elapsed = 0\nonMounted(() => {\n  intervalId = setInterval(() => {\n    elapsed += 1000 / 30\n    x.value = Math.sin(elapsed * 0.001)\n  }, 1000 / 30)\n})\n\nonUnmounted(() => {\n  clearInterval(intervalId)\n})\n</script>\n\n<template>\n  <TresLeches />\n  <TresCanvas :shadows=\"true\" clear-color=\"orange\" :tone-mapping=\"NoToneMapping\">\n    <TresPerspectiveCamera :args=\"[50]\" :position=\"[0, 0.6, 2]\" :look-at=\"[0, 0.5, 0]\" name=\"mainCam\" />\n\n    <OrbitControls />\n    <TresDirectionalLight :position=\"[5, 10, -10]\" :intensity=\"3.14\" />\n    <Box\n      :args=\"[0.4, 0.4, 0.4]\"\n      :cast-shadow=\"true\"\n      :position=\"[-0.5, 0.2, -0.3]\"\n    >\n      <TresMeshStandardMaterial color=\"orange\" />\n    </Box>\n    <Icosahedron\n      :args=\"[0.3]\"\n      :cast-shadow=\"true\"\n      :position=\"[x, 0.3, 0.4]\"\n    >\n      <TresMeshNormalMaterial />\n    </Icosahedron>\n\n    <Sphere\n      :scale=\"0.2\"\n      :position=\"[0.5, 0.4, -0.3]\"\n      :cast-shadow=\"true\"\n    >\n      <TresMeshStandardMaterial color=\"lightblue\" />\n    </Sphere>\n\n    <AccumulativeShadows\n      v-if=\"c.enabled.value.value\"\n      :accumulate=\"c.accumulate.value.value\"\n      :alpha-test=\"c.alphaTest.value.value\"\n      :blend=\"c.blend.value.value\"\n      :color=\"c.isOrange.value.value ? 'orange' : 'blue'\"\n      :color-blend=\"c.colorBlend.value.value\"\n      :frames=\"c.frames.value.value\"\n      :limit=\"c.limit.value.value\"\n      :once=\"c.once.value.value\"\n      :opacity=\"c.opacity.value.value\"\n      :resolution=\"c.resolution.value.value\"\n      :tone-mapped=\"c.toneMapped.value.value\"\n      :scale=\"c.scale.value.value\"\n    />\n    <Suspense>\n      <Environment preset=\"city\" />\n    </Suspense>\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/staging/AlignDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { Align, OrbitControls } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { TresLeches, useControls } from '@tresjs/leches'\nimport '@tresjs/leches/styles'\n\nconst elapsed = shallowRef(0)\nlet intervalId: ReturnType<typeof setInterval>\nonMounted(() => {\n  intervalId = setInterval(() => {\n    elapsed.value += 1000 / 30\n  }, 1000 / 30)\n})\n\nonUnmounted(() => {\n  clearInterval(intervalId)\n})\n\nconst ctrl = useControls({\n  top: false,\n  left: false,\n  front: false,\n  bottom: false,\n  right: false,\n  back: false,\n  disable: false,\n  disableX: false,\n  disableY: false,\n  disableZ: false,\n  useCacheKey: false,\n  vIf: true,\n})\n</script>\n\n<template>\n  <TresLeches />\n  <TresCanvas>\n    <TresPerspectiveCamera :position=\"[0, 0, 5]\" />\n    <OrbitControls />\n    <TresAxesHelper :scale=\"2\" :position=\"[0, 0, 0]\" />\n    <Align\n      v-if=\"ctrl.vIf.value.value\"\n      :left=\"ctrl.left.value.value\"\n      :right=\"ctrl.right.value.value\"\n      :top=\"ctrl.top.value.value\"\n      :bottom=\"ctrl.bottom.value.value\"\n      :front=\"ctrl.front.value.value\"\n      :back=\"ctrl.back.value.value\"\n      :disable=\"ctrl.disable.value.value\"\n      :disable-x=\"ctrl.disableX.value.value\"\n      :disable-y=\"ctrl.disableY.value.value\"\n      :disable-z=\"ctrl.disableZ.value.value\"\n      :cache-key=\"ctrl.useCacheKey.value.value ? (() => Math.floor(elapsed * 0.001)) : undefined\"\n    >\n      <TresMesh :position-x=\"Math.cos(elapsed * 0.001) * 2\" :position-y=\"Math.sin(elapsed * 0.001) * 2\" :scale-z=\"Math.cos(elapsed * 0.001) * 2\">\n        <TresBoxGeometry />\n        <TresMeshNormalMaterial />\n      </TresMesh>\n    </Align>\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/staging/BackdropDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { Backdrop, OrbitControls } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\n\nimport { BasicShadowMap, NoToneMapping, SRGBColorSpace } from 'three'\n\nconst gl = {\n  clearColor: '#82DBC5',\n  shadows: true,\n  alpha: false,\n  shadowMapType: BasicShadowMap,\n  outputColorSpace: SRGBColorSpace,\n  toneMapping: NoToneMapping,\n}\n</script>\n\n<template>\n  <TresCanvas v-bind=\"gl\">\n    <TresPerspectiveCamera :position=\"[11, 11, 11]\" />\n    <OrbitControls />\n    <Backdrop\n      :floor=\"1.5\"\n      :scale=\"[20, 5, 5]\"\n    >\n      <TresMeshPhysicalMaterial\n        :roughness=\"1\"\n        color=\"#efefef\"\n        :side=\"2\"\n      />\n    </Backdrop>\n    <TresAmbientLight :intensity=\"1\" />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/staging/BoundsDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { TresCanvas } from '@tresjs/core'\nimport { Bounds, Grid, OrbitControls } from '@tresjs/cientos'\nimport { Vector3 } from 'three'\nimport { TresLeches, useControls } from '@tresjs/leches'\nimport '@tresjs/leches/styles'\nimport { computed, shallowRef } from 'vue'\n\nconst c = useControls({\n  duration: { value: 0.5, min: 0, max: 10, step: 0.25 },\n  offset: { value: 1, min: -2, max: 2, step: 0.25 },\n  clip: false,\n  useMounted: true,\n  useOrthographic: false,\n  useResize: false,\n  isLinear: false,\n  enabled: true,\n  lookAtX: { value: 0, min: -20, max: 20, step: 0.10 },\n  lookAtY: { value: 0, min: -20, max: 20, step: 0.10 },\n  lookAtZ: { value: 0, min: -20, max: 20, step: 0.10 },\n  moveToX: { value: -5, min: -20, max: 20, step: 0.10 },\n  moveToY: { value: -5, min: -20, max: 20, step: 0.10 },\n  moveToZ: { value: 5, min: -20, max: 20, step: 0.10 },\n  upX: { value: 0, min: -1, max: 1, step: 0.10 },\n  upY: { value: -1, min: -1, max: 1, step: 0.10 },\n  upZ: { value: 0, min: -1, max: 1, step: 0.10 },\n})\n\nconst { sin, cos, PI } = Math\nconst positions = Array.from(\n  { length: 8 },\n  (_, i) => new Vector3(cos(i * PI / 4) * 4, sin(i * PI / 4) * 4, 0),\n)\n\nconst easingFn = computed(() => c.isLinear.value.value ? (n: number) => n : undefined)\n\nconst boundsRef = shallowRef()\n\nconst startArg = shallowRef('')\nconst cancelArg = shallowRef('')\nconst endArg = shallowRef('')\n\nconst startCount = shallowRef(0)\nconst cancelCount = shallowRef(0)\nconst endCount = shallowRef(0)\n\nconst onStartFn = (v: any) => { startArg.value = v.object?.uuid; startCount.value++ }\nconst onCancelFn = (v: any) => { cancelArg.value = v.object?.uuid; cancelCount.value++ }\nconst onEndFn = (v: any) => { endArg.value = v.object?.uuid; endCount.value++ }\n</script>\n\n<template>\n  <TresLeches />\n  <OverlayInfo>\n    <h1>Bounds</h1>\n    <h2>Setup</h2>\n    <p>In this scene, multiple objects are children of <code>&lt;Bounds/&gt;</code>. A <code>pointerup</code> on a child should move/rotate the camera to fit the child into the view.</p>\n    <h2>lookAt(lookAt?, position?, up?)</h2>\n    <p><code>&lt;Bounds&gt;</code> has a <code>fit</code> method that can be called imperatively.</p>\n    <button\n      @pointerup=\"() => boundsRef.instance.lookAt(\n        new Vector3(c.lookAtX.value.value, c.lookAtY.value.value, c.lookAtZ.value.value),\n      )\"\n    >\n      lookAt(new Vector(lookAtArgs))\n    </button><br />\n    <button\n      @pointerup=\"() => boundsRef.instance.lookAt(\n        [c.lookAtX.value.value, c.lookAtY.value.value, c.lookAtZ.value.value],\n      )\"\n    >\n      lookAt([lookAtArgs])\n    </button><br />\n    <button\n      @pointerup=\"() => boundsRef.instance.lookAt(\n        [c.lookAtX.value.value, c.lookAtY.value.value, c.lookAtZ.value.value],\n        [c.moveToX.value.value, c.moveToY.value.value, c.moveToZ.value.value],\n      )\"\n    >\n      lookAt([lookAtArgs], [moveToArgs])\n    </button><br />\n    <button\n      @pointerup=\"() => boundsRef.instance.lookAt(\n        undefined,\n        [c.moveToX.value.value, c.moveToY.value.value, c.moveToZ.value.value],\n      )\"\n    >\n      lookAt(undefined, [moveToArgs])\n    </button><br />\n    <button\n      @pointerup=\"() => boundsRef.instance.lookAt(\n        undefined,\n        [c.moveToX.value.value, c.moveToY.value.value, c.moveToZ.value.value],\n        [c.upX.value.value, c.upY.value.value, c.upZ.value.value],\n      )\"\n    >\n      lookAt(undefined, [moveToArgs], [upArgs])\n    </button><br />\n    <button @pointerup=\"() => boundsRef.instance.lookAt()\">lookAt()</button><br />\n    <h2>Callback results</h2>\n    <p>onStart ({{ startCount }})</p>\n    {{ startArg }}\n    <hr />\n    <p>onCancel ({{ cancelCount }})</p>\n    {{ cancelArg }}\n    <hr />\n    <p>onEnd ({{ endCount }})</p>\n    {{ endArg }}\n    <h2>Testing Notes</h2>\n    <p>OrbitControls zoom using an Orthographic camera can result in parts of the scene appearing \"cut off\", independent of <code>&lt;Bounds/&gt;</code></p>\n    <p>Switching between Orthographic and Perspective Cameras leads to odd behavior, independent of <code>&lt;Bounds/&gt;</code>. To test, change <code>isOrthographicCamera</code>'s value, save and reload the page.</p>\n    <p>The <code>clip</code> option sets the camera's clipping to a large multiple of the internal <code>distance</code>. To test, change the component's coefficient to a smaller number.</p>\n  </OverlayInfo>\n  <TresCanvas render-mode=\"on-demand\">\n    <TresOrthographicCamera v-if=\"c.useOrthographic.value.value\" :position=\"[-5, 5, 5]\" :zoom=\"1\" :args=\"[-400, 400, 400, -400, 0, 10000]\" />\n    <TresPerspectiveCamera v-else :position=\"[5, 5, 5]\" />\n    <OrbitControls make-default />\n    <TresGroup>\n      <Bounds\n        v-if=\"c.enabled.value.value\"\n        ref=\"boundsRef\"\n        :clip=\"c.clip.value.value\"\n        :duration=\"c.duration.value.value\"\n        :offset=\"c.offset.value.value\"\n        :use-resize=\"c.useResize.value.value\"\n        :use-mounted=\"c.useMounted.value.value\"\n        :easing=\"easingFn\"\n        @start=\"onStartFn\"\n        @cancel=\"onCancelFn\"\n        @end=\"onEndFn\"\n      >\n        <TresMesh\n          v-for=\"p, i of positions\"\n          :key=\"i\"\n          :position=\"p\"\n          @pointer-up=\"(e) => boundsRef.instance.lookAt(e.object)\"\n        >\n          <TresBoxGeometry />\n          <TresMeshNormalMaterial />\n        </TresMesh>\n      </Bounds>\n    </TresGroup>\n    <Grid :scale=\"20\" :cell-size=\".1\" :section-size=\"0.3\" section-color=\"#AAF\" :infinite-grid=\"true\" />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/staging/CircleShadowDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { CircleShadow, OrbitControls } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { TresLeches, useControls } from '@tresjs/leches'\nimport '@tresjs/leches/styles'\n\nconst c = useControls({\n  colorRed: true,\n  opacity: { value: 0.5, min: 0.0, max: 1.0 },\n  offset: { value: 0.5, min: 0.0, max: 1.0 },\n  fog: false,\n  depthWrite: false,\n  enabled: true,\n})\n</script>\n\n<template>\n  <TresLeches />\n  <TresCanvas clear-color=\"#82DBC5\">\n    <TresPerspectiveCamera />\n    <OrbitControls />\n    <TresGroup>\n      <TresMesh :position-y=\"1\">\n        <TresBoxGeometry />\n        <TresMeshNormalMaterial />\n      </TresMesh>\n      <CircleShadow\n        v-if=\"c.enabled.value.value\"\n        :scale=\"1.5\"\n        :color=\"c.colorRed.value.value ? 'red' : 'black'\"\n        :offset=\"c.offset.value.value\"\n        :opacity=\"c.opacity.value.value\"\n        :fog=\"c.fog.value.value\"\n        :depth-write=\"c.depthWrite.value.value\"\n      />\n    </TresGroup>\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/staging/ContactShadowsDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { Box, ContactShadows, Icosahedron, OrbitControls, TorusKnot } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { TresLeches, useControls } from '@tresjs/leches'\nimport { BasicShadowMap, NoToneMapping, SRGBColorSpace } from 'three'\nimport { reactive, shallowRef } from 'vue'\nimport '@tresjs/leches/styles'\n\nconst gl = {\n  clearColor: '#CCC',\n  shadows: true,\n  alpha: false,\n  shadowMapType: BasicShadowMap,\n  outputColorSpace: SRGBColorSpace,\n  toneMapping: NoToneMapping,\n}\n\nconst state = reactive({\n  width: 1,\n  height: 1,\n  opacity: 1,\n  blur: 3.5,\n  near: 0,\n  far: 10,\n  smooth: true,\n  resolution: 512,\n  scale: 10,\n  tint: '#000000',\n  color: '#0000ff',\n  depthWrite: false,\n  rotationX: 0,\n})\n\nconst { width, height, blur, far, smooth, opacity, resolution, scale, tint, color, depthWrite, rotationX } = useControls({\n  width: {\n    value: state.width,\n    step: 0.1,\n    min: 0.1,\n    max: 10,\n  },\n  height: {\n    value: state.height,\n    step: 0.1,\n    min: 0.1,\n    max: 10,\n  },\n  near: {\n    value: state.near,\n    step: 0.1,\n    min: 0,\n    max: 30,\n  },\n  far: {\n    value: state.far,\n    step: 0.1,\n    min: 0,\n    max: 30,\n  },\n  scale: {\n    value: state.scale,\n    step: 0.1,\n    min: 0.1,\n    max: 30,\n  },\n  blur: {\n    value: state.blur,\n    step: 0.1,\n    min: 0,\n    max: 10,\n  },\n  smooth: state.smooth,\n  opacity: {\n    value: state.opacity,\n    step: 0.1,\n    min: 0,\n    max: 1,\n  },\n  resolution: {\n    value: state.resolution,\n    step: 1,\n    min: 0,\n    max: 1024,\n  },\n  tint: {\n    type: 'color',\n    value: state.tint,\n  },\n  color: {\n    type: 'color',\n    value: state.color,\n  },\n  depthWrite: state.depthWrite,\n  rotationX: {\n    value: state.rotationX,\n    step: 0.1,\n    max: 9,\n  },\n})\n\nwatch(() => [\n  width.value.value,\n  height.value.value,\n  blur.value.value,\n  far.value.value,\n  smooth.value.value,\n  opacity.value.value,\n  resolution.value.value,\n  scale.value.value,\n  color.value.value,\n  tint.value.value,\n  depthWrite.value.value,\n  rotationX.value.value,\n], () => {\n  state.width = width.value.value\n  state.height = height.value.value\n  state.blur = blur.value.value\n  state.far = far.value.value\n  state.smooth = smooth.value.value\n  state.opacity = opacity.value.value\n  state.resolution = resolution.value.value\n  state.tint = tint.value.value\n  state.color = color.value.value\n  state.scale = scale.value.value\n  state.depthWrite = depthWrite.value.value\n  state.rotationX = rotationX.value.value\n})\n\nconst boxRef = shallowRef({ instance: { rotation: { x: 0, y: 0, z: 0 } } })\nconst icoRef = shallowRef({ instance: { rotation: { x: 0, y: 0, z: 0 } } })\nconst torusRef = shallowRef({ instance: { rotation: { x: 0, y: 0, z: 0 } } })\n\nconst intervalId = setInterval(() => {\n  boxRef.value.instance.rotation.x += 0.01\n  boxRef.value.instance.rotation.z += 0.01\n  icoRef.value.instance.rotation.x += 0.01\n  icoRef.value.instance.rotation.z += 0.01\n  torusRef.value.instance.rotation.x += 0.01\n  torusRef.value.instance.rotation.z += 0.01\n}, 20)\n\nonUnmounted(() => clearInterval(intervalId))\n</script>\n\n<template>\n  <TresLeches />\n  <TresCanvas v-bind=\"gl\">\n    <TresPerspectiveCamera :args=\"[50]\" :position=\"[0.5, 1, 2]\" />\n\n    <OrbitControls />\n    <Box\n      ref=\"boxRef\"\n      :args=\"[0.4, 0.4, 0.4]\"\n      :position=\"[\n        Math.cos((0 / 3) * 2 * Math.PI) * 0.5,\n        0.5,\n        Math.sin((0 / 3) * 2 * Math.PI) * 0.5,\n      ]\"\n    >\n      <TresMeshNormalMaterial />\n    </Box>\n    <Icosahedron\n      ref=\"icoRef\"\n      :args=\"[0.3]\"\n      :position=\"[\n        Math.cos((1 / 3) * 2 * Math.PI) * 0.5,\n        0.5,\n        Math.sin((1 / 3) * 2 * Math.PI) * 0.5,\n      ]\"\n    >\n      <TresMeshNormalMaterial />\n    </Icosahedron>\n\n    <TorusKnot\n      ref=\"torusRef\"\n      :args=\"[0.4, 0.05, 256, 24, 1, 3]\"\n      :position=\"[\n        Math.cos((2 / 3) * 2 * Math.PI) * 0.5,\n        0.5,\n        Math.sin((2 / 3) * 2 * Math.PI) * 0.5,\n      ]\"\n    >\n      <TresMeshNormalMaterial />\n    </TorusKnot>\n    <TresGroup>\n      <ContactShadows v-bind=\"state\" :position-y=\"0.0001\" />\n      <!-- <TresMesh :rotation-x=\"-Math.PI / 2\" :scale=\"10\">\n        <TresPlaneGeometry />\n        <TresMeshBasicMaterial color=\"gray\" />\n      </TresMesh> -->\n    </TresGroup>\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/staging/GridDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { Grid, OrbitControls } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\n\nconst gl = {\n  clearColor: '#000000',\n}\n\nconst cellColor = shallowRef('#000000')\nconst sectionColor = shallowRef('#000000')\nconst cellThickness = shallowRef(0)\nconst sectionThickness = shallowRef(0)\nconst cellSize = shallowRef(0)\nconst sectionSize = shallowRef(0)\nlet elapsed = 0\nsetInterval(() => {\n  elapsed += 1000 / 30\n  cellColor.value = Math.cos(elapsed * 0.01) > 0 ? '#FFFF00' : '#FF0000'\n  sectionColor.value = Math.sin(elapsed * 0.01) > 0 ? '#FF0000' : '#00FF00'\n  sectionThickness.value = Math.cos(elapsed * 0.003) + 1\n  cellThickness.value = Math.cos(elapsed * 0.001) + 1\n  cellSize.value = Math.sin(elapsed * 0.0001) + 2\n  sectionSize.value = Math.cos(elapsed * 0.0001) + 2\n}, 1000 / 30)\n</script>\n\n<template>\n  <TresCanvas v-bind=\"gl\">\n    <TresPerspectiveCamera :position=\"[15, 18, 18]\" :fov=\"25\" />\n    <OrbitControls />\n    <Grid\n      :args=\"[10.5, 10.5]\"\n      :cell-size=\"cellSize\"\n      :cell-color=\"cellColor\"\n      :cell-thickness=\"cellThickness\"\n      :section-size=\"sectionSize\"\n      :section-thickness=\"sectionThickness\"\n      :section-color=\"sectionColor\"\n      :infinite-grid=\"true\"\n      :fade-from=\"0\"\n      :fade-distance=\"12\"\n      :fade-strength=\"1\"\n    />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/staging/OceanDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { Ocean, OrbitControls, Sky } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { ACESFilmicToneMapping, SRGBColorSpace } from 'three'\n\nconst gl = {\n  clearColor: '#333',\n  outputColorSpace: SRGBColorSpace,\n  toneMapping: ACESFilmicToneMapping,\n  toneMappingExposure: 1,\n}\n</script>\n\n<template>\n  <TresCanvas\n    v-bind=\"gl\"\n  >\n    <TresPerspectiveCamera :position=\"[0, 0, 15]\" />\n    <TresDirectionalLight :position=\"[0, 0, 1]\" />\n    <Sky :azimuth=\"0\" />\n    <Suspense>\n      <Ocean>\n        <TresCircleGeometry :args=\"[50, 16]\" />\n      </Ocean>\n    </Suspense>\n    <TresMesh :position-y=\"1\">\n      <TresBoxGeometry :args=\"[1, 1, 1]\" />\n    </TresMesh>\n    <OrbitControls\n      :enable-pan=\"false\"\n      :enable-zoom=\"false\"\n      :max-polar-angle=\"Math.PI * 0.495\"\n      :min-distance=\"40.0\"\n      :max-distance=\"200.0\"\n    />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/staging/PrecipitationDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { OrbitControls, Precipitation } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { TresLeches, useControls } from '@tresjs/leches'\nimport { NoToneMapping, SRGBColorSpace } from 'three'\nimport { reactive, shallowRef } from 'vue'\nimport '@tresjs/leches/styles'\n\nconst gl = {\n  clearColor: '#333',\n  outputColorSpace: SRGBColorSpace,\n  toneMapping: NoToneMapping,\n}\n\nconst precipitationRef = shallowRef()\n\nconst options = reactive({\n  speed: 1,\n  randomness: 0,\n  count: 1000,\n  size: 0.1,\n  areaX: 25,\n  areaY: 25,\n  areaZ: 25,\n})\n\nconst { speed, randomness, count, size, areaX, areaY, areaZ } = useControls({\n  speed: {\n    value: options.speed,\n    step: 0.1,\n    min: 0,\n    max: 10,\n  },\n  randomness: {\n    value: options.randomness,\n    step: 0.1,\n    min: 0,\n    max: 10,\n  },\n  count: {\n    value: options.count,\n    step: 10,\n    min: 500,\n    max: 30000,\n  },\n  size: {\n    value: options.size,\n    step: 0.001,\n    min: 0.001,\n    max: 1,\n  },\n  areaX: {\n    value: options.areaX,\n    step: 1,\n    min: 1,\n    max: 30,\n  },\n  areaY: {\n    value: options.areaY,\n    step: 1,\n    min: 1,\n    max: 30,\n  },\n  areaZ: {\n    value: options.areaZ,\n    step: 1,\n    min: 1,\n    max: 30,\n  },\n})\n\nwatch([speed.value, randomness.value, count.value, size.value, areaX.value, areaY.value, areaZ.value], () => {\n  options.speed = speed.value.value\n  options.randomness = randomness.value.value\n  options.count = count.value.value\n  options.size = size.value.value\n  options.areaX = areaX.value.value\n  options.areaY = areaY.value.value\n  options.areaZ = areaZ.value.value\n})\n</script>\n\n<template>\n  <TresLeches />\n  <TresCanvas v-bind=\"gl\">\n    <TresPerspectiveCamera :position=\"[0, 2, 15]\" />\n    <Precipitation\n      ref=\"precipitationRef\"\n      :speed=\"options.speed\"\n      :area=\"[options.areaX, options.areaY, options.areaZ]\"\n      :count=\"options.count\"\n      :randomness=\"options.randomness\"\n      :size=\"options.size\"\n    />\n    <TresGridHelper :args=\"[10, 10]\" />\n    <OrbitControls />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/staging/SkyDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { OrbitControls, Sky } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { TresLeches, useControls } from '@tresjs/leches'\nimport { ACESFilmicToneMapping, SRGBColorSpace } from 'three'\nimport '@tresjs/leches/styles'\n\nconst gl = {\n  clearColor: '#333',\n  outputColorSpace: SRGBColorSpace,\n  toneMapping: ACESFilmicToneMapping,\n  toneMappingExposure: 1,\n}\n\nconst { turbidity, rayleigh, mieCoefficient, mieDirectionalG, elevation, azimuth, distance, exposure } = useControls({\n  turbidity: { value: 3.4, min: 0, max: 20, step: 0.1 },\n  rayleigh: { value: 3, min: 0, max: 4, step: 0.1 },\n  mieCoefficient: { value: 0.005, min: 0, max: 0.1, step: 0.001 },\n  mieDirectionalG: { value: 0.7, min: 0, max: 0.99, step: 0.01 },\n  elevation: { value: 2, min: 0, max: 90, step: 0.1 },\n  azimuth: { value: 180, min: 0, max: 360, step: 1 },\n  distance: { value: 450000, min: 1000, max: 1000000, step: 1000 },\n  exposure: { value: 0.5, min: 0, max: 1, step: 0.01 },\n})\n</script>\n\n<template>\n  <TresLeches class=\"important-fixed important-left-2 important-w-90\" />\n  <TresCanvas\n    v-bind=\"gl\"\n    :tone-mapping-exposure=\"exposure.value\"\n  >\n    <TresPerspectiveCamera :position=\"[0, 100, 2000]\" />\n    <Sky\n      :elevation=\"elevation.value\"\n      :azimuth=\"azimuth.value\"\n      :mie-coefficient=\"mieCoefficient.value\"\n      :mie-directional-g=\"mieDirectionalG.value\"\n      :rayleigh=\"rayleigh.value\"\n      :turbidity=\"turbidity.value\"\n      :distance=\"distance.value\"\n    />\n    <OrbitControls\n      :enable-pan=\"false\"\n      :enable-zoom=\"false\"\n    />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/staging/SmokeDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { Box, OrbitControls, Smoke } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { NoToneMapping, SRGBColorSpace } from 'three'\n\nconst gl = {\n  clearColor: '#333',\n  alpha: true,\n  outputColorSpace: SRGBColorSpace,\n  toneMapping: NoToneMapping,\n}\n</script>\n\n<template>\n  <TresCanvas\n    v-bind=\"gl\"\n  >\n    <TresPerspectiveCamera :position=\"[0, 2, 5]\" />\n    <Suspense>\n      <Smoke\n        :position=\"[-4, -2, 0]\"\n        :segments=\"8\"\n      />\n    </Suspense>\n    <Suspense>\n      <Smoke\n        :position=\"[-4, 2, 0]\"\n        :segments=\"8\"\n      />\n    </Suspense>\n    <Suspense>\n      <Smoke :segments=\"8\" />\n    </Suspense>\n    <Suspense>\n      <Smoke\n        :position=\"[4, -2, 0]\"\n        :segments=\"8\"\n      />\n    </Suspense>\n    <Suspense>\n      <Smoke\n        :position=\"[4, 2, 0]\"\n        :segments=\"8\"\n      />\n    </Suspense>\n    <Box :args=\"[2, 2]\">\n      <TresMeshToonMaterial color=\"#82DBC5\" />\n    </Box>\n    <TresGridHelper :args=\"[10, 10]\" />\n    <TresAmbientLight :intensity=\"1\" />\n    <TresDirectionalLight\n      :intensity=\"1\"\n      :position=\"[2, 2, 2]\"\n    />\n    <OrbitControls />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/staging/SoftShadowsDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { TresCanvas } from '@tresjs/core'\nimport { OrbitControls, SoftShadows } from '@tresjs/cientos'\nimport { Group, MeshPhongMaterial, SphereGeometry, Vector3 } from 'three'\nimport { TresLeches, useControls } from '@tresjs/leches'\nimport '@tresjs/leches/styles'\n\nconst c = useControls({\n  samples: { value: 5, min: 1, max: 10, step: 1 },\n})\nconst sphereGeo = new SphereGeometry(0.3, 20, 20)\nconst sphereMat = new MeshPhongMaterial({ color: '#82dbc5' })\nconst spherePositions = Array.from({ length: 10 }).fill(null).map(() => new Vector3())\nlet ii = 0\nfor (const p of spherePositions) {\n  p.x = ii * 0.5 - 2.5\n  ii++\n}\n\nconst spheres = shallowRef(new Group())\nlet intervalId: ReturnType<typeof setInterval>\nonMounted(() => {\n  intervalId = setInterval(() => {\n    for (const sphere of spheres.value.children) {\n      sphere.userData.phase += 0.01\n      sphere.position.y = Math.sin(sphere.userData.phase) ** 2 * 3 + 0.5\n    }\n  }, 1000 / 30)\n})\n\nonUnmounted(() => {\n  clearInterval(intervalId)\n})\n</script>\n\n<template>\n  <TresLeches />\n  <TresCanvas :shadows=\"true\" :shadowMap-enabled=\"true\">\n    <TresFog :args=\"['#FFFFFF', 5, 100]\" />\n\n    <OrbitControls />\n    <TresPerspectiveCamera :position=\"[5, 9, -5]\" :fov=\"60\" />\n\n    <TresAmbientLight color=\"#AAAAAA\" :intensity=\"2\" />\n    <TresDirectionalLight\n      color=\"#F0F6FF\"\n      :intensity=\"6\"\n      :position=\"[2, 8, 4]\"\n      :cast-shadow=\"true\"\n      :shadow-mapSize-width=\"1024\"\n      :shadow-mapSize-height=\"1024\"\n      :shadow-camera-far=\"20\"\n    />\n\n    <SoftShadows :samples=\"c.samples.value\" />\n\n    <TresMesh :position=\"[0, 1.5, 1]\" :scale-y=\"3\" :cast-shadow=\"true\" :receive-shadow=\"true\" name=\"column\">\n      <TresBoxGeometry />\n      <TresMeshPhongMaterial color=\"#82dbc5\" />\n    </TresMesh>\n\n    <TresMesh :rotation-x=\"-Math.PI / 2\" :receive-shadow=\"true\" name=\"ground\">\n      <TresPlaneGeometry :args=\"[100, 100, 8, 8]\" />\n      <TresMeshPhongMaterial color=\"#fbb03b\" />\n    </TresMesh>\n\n    <TresGroup ref=\"spheres\" name=\"spheres\">\n      <TresMesh\n        v-for=\"p, i of spherePositions\"\n        :key=\"i\"\n        :material=\"sphereMat\"\n        :geometry=\"sphereGeo\"\n        :position=\"p\"\n        :cast-shadow=\"true\"\n        :receive-shadow=\"true\"\n        :userData-phase=\"i * 0.3\"\n      />\n    </TresGroup>\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/staging/SparklesDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { Sparkles, Sphere } from '@tresjs/cientos'\nimport { TresCanvas, useRenderLoop } from '@tresjs/core'\nimport { TresLeches, useControls } from '@tresjs/leches'\nimport { Color } from 'three'\nimport { shallowRef } from 'vue'\nimport '@tresjs/leches/styles'\n\nconst lightRef = shallowRef()\nconst { value: mix } = useControls({ mix: { value: 0, min: 0, max: 1 } })\nconst { value: threshold } = useControls({ threshold: { value: 0.5, min: 0, max: 1 } })\n\nuseRenderLoop().onLoop(({ elapsed }) => {\n  if (lightRef.value) {\n    lightRef.value.position.x = Math.cos(elapsed) * 2.5\n    lightRef.value.position.y = Math.sin(elapsed) * 2.5\n    lightRef.value.position.z = Math.sin(lightRef.value.position.y * Math.PI * 0.25) * 2\n  }\n})\n</script>\n\n<template>\n  <TresLeches class=\"top-0 important-left-4\" />\n  <TresCanvas clear-color=\"#333\">\n    <TresPerspectiveCamera />\n    <TresDirectionalLight ref=\"lightRef\">\n      <Sphere\n        color=\"white\"\n        :scale=\"0.1\"\n      />\n    </TresDirectionalLight>\n    <Sphere :args=\"[0.5, 64, 64]\">\n      <TresMeshStandardMaterial :color=\"new Color('#222')\" />\n      <Sparkles\n        :directional-light=\"lightRef\"\n        :mix-alpha=\"mix\"\n        :mix-color=\"mix\"\n        :mix-offset=\"mix\"\n        :mix-size=\"mix\"\n        :mix-surface-distance=\"mix\"\n        :normal-threshold=\"threshold\"\n        :noise-scale=\"100\"\n        :sequence-surface-distance=\"[0.1, 1.0]\"\n        :sequence-alpha=\"[[0.0, 0.1], [0.2, 1.0], [0.9, 1.0]]\"\n        :sequence-offset=\"[[0.5, [0, 0, 0]], [0.6, [0, -1, 0]]]\"\n        :alpha=\"1.0\"\n      />\n    </Sphere>\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/staging/StageDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { Grid, OrbitControls, Stage } from '@tresjs/cientos'\nimport type { LoaderProto } from '@tresjs/core'\nimport { TresCanvas, useLoader } from '@tresjs/core'\nimport type { Object3D } from 'three'\nimport { Mesh, MeshStandardMaterial, NoToneMapping, SRGBColorSpace } from 'three'\nimport type { GLTF } from 'three-stdlib'\nimport { GLTFLoader } from 'three-stdlib'\n\nconst controlsOptions = {\n  lighting: ['rembrandt', 'portrait', 'upfront', 'soft', null, undefined, true, false, { main: [1, 1, 1], fill: [0, -1, 0] }],\n  intensity: [0.5, 0, 1, 2, 1000],\n  shadows: [\n    'contact',\n    { type: 'contact', offset: 0.2 },\n    'accumulative',\n    { type: 'accumulative', alphaTest: 1 },\n    { type: 'accumulative', alphaTest: 0.5, ambient: 0 },\n    { type: 'accumulative', alphaTest: 0.5, ambient: 1 },\n    null,\n    undefined,\n    true,\n    false,\n  ],\n  adjustCamera: [true, false, 0, 0.5, 1, 2, 5],\n  environment: ['city', { preset: 'city', blur: 1 }, 'umbrellas', { preset: 'night' }, null, undefined],\n  align: [\n    { top: true },\n    undefined,\n    { top: true, disableX: true },\n    { bottom: true, disableZ: true },\n  ],\n  enabled: [true, false],\n  test_torusKnotEnabled: [false, true],\n  test_giantTorusKnotEnabled: [false, true],\n} as const\n\nconst controls = Object.entries(controlsOptions).reduce((acc, [k, v]) => { acc[k] = { options: v, selected: shallowRef(v[0]) }; return acc }, {})\n\nconst gl = {\n  clearColor: '#82DBC5',\n  outputColorSpace: SRGBColorSpace,\n  toneMapping: NoToneMapping,\n  shadows: true,\n}\n\nconst scene = await useLoader(GLTFLoader as LoaderProto<GLTF>, 'https://raw.githubusercontent.com/Tresjs/assets/215208b4a54736965d525ab9c47d82dbfe4b2a02/models/gltf/suzanne/suzanne.glb') as unknown as { nodes: { Suzanne: Object3D } }\n\nconst nodes = scene.nodes\n\nnodes.Suzanne.traverse((obj) => {\n  if (obj instanceof Mesh) {\n    obj.material = new MeshStandardMaterial({ color: '#fbb03b', metalness: 1, roughness: 0 })\n  }\n})\n\nconst onChange = (e: Event) => {\n  const id = e.target!.id\n  const i = e.target!.selectedIndex\n  controls[id].selected.value = controls[id].options[i]\n}\n</script>\n\n<template>\n  <OverlayInfo>\n    <h1>Stage</h1>\n    <h2>Props</h2>\n    <template\n      v-for=\"[title, { options }] of Object.entries(controls)\"\n      :key=\"title\"\n    >\n      <h3>{{ title }}</h3>\n      <select :id=\"title\" :name=\"title\" @change=\"onChange\">\n        <option\n          v-for=\"option, i of options\"\n          :key=\"i\"\n          :value=\"option\"\n        >\n          <template v-if=\"option === null\">null</template>\n          <template v-else-if=\"option === undefined\">undefined</template>\n          <template v-else>{{ option }}</template>\n        </option>\n      </select>\n      <br />\n    </template>\n  </OverlayInfo>\n  <TresCanvas v-bind=\"gl\">\n    <TresPerspectiveCamera :position=\"[0, 5, 15]\" />\n    <OrbitControls make-default />\n    <Stage\n      v-if=\"controls.enabled.selected.value\"\n      :adjust-camera=\"controls.adjustCamera.selected.value\"\n      :align=\"controls.align.selected.value\"\n      :lighting=\"controls.lighting.selected.value\"\n      :shadows=\"controls.shadows.selected.value\"\n      :environment=\"controls.environment.selected.value\"\n      :intensity=\"controls.intensity.selected.value\"\n    >\n      <TresGroup>\n        <Suspense>\n          <primitive\n            :object=\"nodes.Suzanne\"\n            :rotation=\"[5.6548, Math.PI, 0]\"\n            :position=\"[0, 0.90, 1]\"\n            cast-shadow\n          />\n        </Suspense>\n\n        <TresMesh cast-shadow :position=\"[1.5, 0.5, -1.5]\">\n          <TresBoxGeometry />\n          <TresMeshStandardMaterial color=\"#82dbc5\" />\n        </TresMesh>\n\n        <TresMesh cast-shadow :position=\"[-1.5, 1, -1.5]\">\n          <TresSphereGeometry />\n          <TresMeshStandardMaterial color=\"#4f4f4f\" />\n        </TresMesh>\n\n        <TresMesh\n          v-if=\"controls.test_torusKnotEnabled.selected.value\"\n          :position=\"[3, 2, 1]\"\n          cast-shadow\n        >\n          <TresTorusKnotGeometry />\n          <TresMeshNormalMaterial />\n        </TresMesh>\n\n        <TresMesh\n          v-if=\"controls.test_giantTorusKnotEnabled.selected.value\"\n          :scale=\"10\"\n          :position=\"[0, 0, -20]\"\n        >\n          <TresTorusKnotGeometry />\n          <TresMeshNormalMaterial />\n        </TresMesh>\n      </TresGroup>\n    </Stage>\n    <Grid :position-y=\"0.01\" :scale=\"10\" :section-size=\"0.1\" section-color=\"#4f4f6f\" :cell-size=\"0.025\" infinite-grid :fade-distance=\"8\" :fade-from=\"0\" />\n    <TresAmbientLight :intensity=\"0.5\" />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/staging/StarsDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { MouseParallax, OrbitControls, Stars } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport { TresLeches, useControls } from '@tresjs/leches'\nimport { NoToneMapping, SRGBColorSpace } from 'three'\nimport { reactive, shallowRef } from 'vue'\nimport '@tresjs/leches/styles'\n\nconst gl = {\n  clearColor: '#333',\n  outputColorSpace: SRGBColorSpace,\n  toneMapping: NoToneMapping,\n}\nconst options = reactive({\n  size: 0.1,\n  sizeAttenuation: true,\n  count: 5000,\n  depth: 50,\n  radius: 100,\n})\n\nconst { radius, depth, count, size, 'size attenuation': sizeAttenuation } = useControls({\n  'radius': {\n    value: options.radius,\n    step: 5,\n    min: 0,\n    max: 300,\n  },\n  'depth': {\n    value: options.depth,\n    step: 1,\n    min: 0,\n    max: 50,\n  },\n  'count': {\n    value: options.count,\n    step: 100,\n    min: 1000,\n    max: 15000,\n  },\n  'size': {\n    value: options.size,\n    step: 0.1,\n    min: 0,\n    max: 50,\n  },\n  'size attenuation': options.sizeAttenuation,\n})\n\nwatch([radius.value, depth.value, count.value, size.value, sizeAttenuation.value], () => {\n  options.radius = radius.value.value\n  options.depth = depth.value.value\n  options.count = count.value.value\n  options.size = size.value.value\n  options.sizeAttenuation = sizeAttenuation.value.value\n})\n\nconst star = shallowRef<Stars>(null)\n</script>\n\n<template>\n  <TresLeches />\n  <TresCanvas v-bind=\"gl\">\n    <TresPerspectiveCamera :position=\"[0, 2, 5]\" />\n    <MouseParallax :factor=\"0.5\" />\n    <Stars\n      ref=\"star\"\n      :radius=\"options.radius\"\n      :depth=\"options.depth\"\n      :count=\"options.count\"\n      :size=\"options.size\"\n      :size-attenuation=\"options.sizeAttenuation\"\n    />\n    <TresGridHelper :args=\"[10, 10]\" />\n    <OrbitControls />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/staging/environment/EnvironmentDemo.vue",
    "content": "<!-- eslint-disable no-console -->\n<script setup lang=\"ts\">\nimport { Environment, Lightformer, OrbitControls, Sphere, useProgress } from '@tresjs/cientos'\nimport { TresCanvas } from '@tresjs/core'\nimport Lightformers from './Lightformers.vue'\nimport { TresLeches, useControls } from '@tresjs/leches'\nimport { BasicShadowMap, NoToneMapping, SRGBColorSpace, Vector3 } from 'three'\nimport '@tresjs/leches/styles'\n\n/* const environmentFiles = ['/px.jpg', '/nx.jpg', '/py.jpg', '/ny.jpg', '/pz.jpg', '/nz.jpg'] */\n\nconst gl = {\n  clearColor: '#82DBC5',\n  shadows: true,\n  alpha: false,\n  shadowMapType: BasicShadowMap,\n  outputColorSpace: SRGBColorSpace,\n  toneMapping: NoToneMapping,\n}\n\nconst { background, blur, preset, backgroundIntensity, environmentIntensity, backgroundRotation, environmentRotation, syncMaterials } = useControls({\n  background: true,\n  blur: {\n    value: 0,\n    min: 0,\n    max: 1,\n    step: 0.01,\n  },\n  preset: {\n    options: [\n      'sunset',\n      'studio',\n      'city',\n      'umbrellas',\n      'night',\n      'forest',\n      'snow',\n      'dawn',\n      'hangar',\n      'urban',\n      'modern',\n      'shangai',\n    ],\n    value: 'sunset',\n  },\n  backgroundIntensity: {\n    value: 1,\n    min: 0,\n    max: 1,\n    step: 0.1,\n  },\n  environmentIntensity: {\n    value: 1,\n    min: 0,\n    max: 1,\n    step: 0.1,\n  },\n  backgroundRotation: {\n    value: new Vector3(0, 0, 0),\n  },\n  environmentRotation: {\n    value: new Vector3(0, 0, 0),\n  },\n  syncMaterials: false,\n})\n\nconst environmentRef = ref(null)\n\nwatchEffect(() => {\n  console.log(background.value.value)\n})\n\nwatchEffect(() => {\n  console.log(environmentRef.value)\n})\n\nconst { progress, hasFinishLoading } = await useProgress()\n</script>\n\n<template>\n  <Transition\n    name=\"fade-overlay\"\n    enter-active-class=\"opacity-1 transition-opacity duration-200\"\n    leave-active-class=\"opacity-0 transition-opacity duration-200\"\n  >\n    <div\n      v-show=\"!hasFinishLoading\"\n      class=\"absolute bg-white t-0 l-0 w-full h-full z-20 flex justify-center items-center text-black font-mono\"\n    >\n      <div class=\"w-200px\">\n        Loading... {{ progress }} %\n        <i class=\"i-ic-twotone-catching-pokemon animate-rotate-in\"></i>\n      </div>\n    </div>\n  </Transition>\n  <TresLeches />\n  <TresCanvas v-bind=\"gl\">\n    <TresPerspectiveCamera :position=\"[10, 10, 10]\" />\n    <OrbitControls />\n    <Suspense>\n      <!-- <Environment\n        ref=\"environmentRef\"\n        :background=\"background.value\"\n        :files=\"environmentFiles\"\n        :blur=\"blur.value\"\n        path=\"https://raw.githubusercontent.com/Tresjs/assets/main/textures/environmentMap\"\n      /> -->\n      <Environment\n        :background=\"background.value\"\n        :blur=\"blur.value\"\n        :preset=\"preset.value\"\n        :frames=\"Infinity\"\n        :background-intensity=\"backgroundIntensity.value\"\n        :environment-intensity=\"environmentIntensity.value\"\n        :background-rotation=\"[backgroundRotation.value.x, backgroundRotation.value.y, backgroundRotation.value.z]\"\n        :environment-rotation=\"[environmentRotation.value.x, environmentRotation.value.y, environmentRotation.value.z]\"\n        :sync-materials=\"syncMaterials.value\"\n      >\n        <Lightformer\n          :intensity=\"0.75\"\n          :rotation-x=\"Math.PI / 2\"\n          :position=\"[0, 5, -9]\"\n          :scale=\"[10, 10, 1]\"\n        />\n        <Lightformers />\n      </Environment>\n    </Suspense>\n    <Sphere>\n      <TresMeshStandardMaterial\n        color=\"yellow\"\n        :roughness=\"0\"\n        :metalness=\"0.5\"\n      />\n    </Sphere>\n    <TresGridHelper />\n    <TresAmbientLight :intensity=\"1\" />\n  </TresCanvas>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/staging/environment/Lightformers.vue",
    "content": "<script setup lang=\"ts\">\nimport { useControls } from '@tresjs/leches'\nimport { useLoop } from '@tresjs/core'\nimport { ref } from 'vue'\nimport { Lightformer } from '@tresjs/cientos'\n\nconst { lightformers } = useControls({\n  lightformers: false,\n})\n\nconst lightformerRef = ref(null)\n\nconst { onBeforeRender } = useLoop()\n\nonBeforeRender(({ elapsed }) => {\n  if (lightformerRef.value) {\n    lightformerRef.value.mesh.position.y = Math.sin(elapsed) * 2\n  }\n})\n</script>\n\n<template>\n  <TresGroup v-if=\"lightformers\">\n    <Lightformer\n      ref=\"lightformerRef\"\n      :intensity=\"1\"\n      color=\"red\"\n      form=\"ring\"\n      :rotation-x=\"Math.PI / 2\"\n      :position=\"[0, 5, -9]\"\n      :scale=\"[10, 10, 1]\"\n    />\n    <Lightformer\n      :intensity=\"4\"\n      :rotation-y=\"Math.PI / 2\"\n      :position=\"[-5, 1, -1]\"\n      :scale=\"[20, 0.1, 1]\"\n    />\n    <Lightformer\n      :rotation-y=\"Math.PI / 2\"\n      :position=\"[-5, -1, -1]\"\n      :scale=\"[20, 0.5, 1]\"\n    />\n    <Lightformer\n      :rotation-y=\"-Math.PI / 2\"\n      :position=\"[10, 1, 0]\"\n      :scale=\"[20, 11, 1]\"\n    />\n  </TresGroup>\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/staging/fit/FitDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { Fit, OrbitControls } from '@tresjs/cientos'\nimport { useLoop,\n} from '@tresjs/core'\nimport { Vector3 } from 'three'\nimport type { TresObject3D } from '@tresjs/core'\nimport RandUtils from '../../../../../../src/core/abstractions/Lensflare/RandUtils'\n\ndefineProps<{\n  choice: Ref<TresObject3D>\n  object: Ref<TresObject3D>\n}>()\nfunction getPositions(seed: number, count = 40, radius = 10) {\n  // NOTE: Generate some randomish positions for\n  // some child components of `<Fit />`\n  const positions: Vector3[] = []\n  const rng = new RandUtils(seed)\n  const rand = () => rng.rand()\n  const offsetX = rand() * 10\n  const offsetY = rand() * 10\n  const offsetZ = rand() * 10\n  const radX = rand() * radius + 1\n  const radY = rand() * radius + 1\n  const radZ = rand() * radius + 1\n  for (let i = 0; i < count; i++) {\n    positions.push(\n      new Vector3(\n        rand() * radX + offsetX,\n        rand() * radY + offsetY,\n        rand() * radZ + offsetZ,\n      ),\n    )\n  }\n  return positions\n}\n\n// NOTE: Create some refs so we can scale, rotate, and twist\n// the container and `<Fit />` elements. We want to make sure\n// that it works in chains with the usual transforms.\nconst [sx0, sy0, sz0, rx0, ry0, rz0, x0, y0, z0, sx1, sy1, sz1, rx1, ry1, rz1, x1, y1, z1, sx2, sy2, sz2, rx2, ry2, rz2, x2, y2, z2, x3, y3] = Array.from({ length: 30 })\n  .fill(0)\n  .map(_ => shallowRef(0))\nconst fit0 = shallowRef({ fit: () => {} })\nconst fit1 = shallowRef({ fit: () => {} })\nconst fit2 = shallowRef({ fit: () => {} })\nconst { sin, cos, PI } = Math\n\nconst { onBeforeRender } = useLoop()\n\nonBeforeRender(({ elapsed }) => {\n  rx0.value = sin(elapsed * 0.05) * PI\n  ry0.value = sin(elapsed * 0.11) * PI\n  rz0.value = sin(elapsed * 0.22) * PI\n  rx1.value = sin(elapsed * 0.66) * PI\n  ry1.value = sin(elapsed * 0.77) * PI\n  rz1.value = sin(elapsed * 0.88) * PI\n  rx2.value = sin(elapsed * 1.33) * PI\n  ry2.value = sin(elapsed * 1.44) * PI\n  rz2.value = sin(elapsed * 1.55) * PI\n\n  x0.value = sin(elapsed * 0.33)\n  y0.value = sin(elapsed * 0.44)\n  z0.value = sin(elapsed * 0.55)\n  x1.value = sin(elapsed * 0.99)\n  y1.value = sin(elapsed * 1.11)\n  z1.value = sin(elapsed * 1.22)\n  x2.value = sin(elapsed * 1.66)\n  y2.value = sin(elapsed * 1.77)\n  z2.value = sin(elapsed * 1.88)\n\n  x3.value = sin(elapsed)\n  y3.value = cos(elapsed)\n\n  sx0.value = cos(elapsed * 0.22)\n  sy0.value = cos(elapsed * 0.33)\n  sz0.value = cos(elapsed * 0.33)\n  sx1.value = cos(elapsed * 0.22)\n  sy1.value = cos(elapsed * 0.44)\n  sz1.value = cos(elapsed * 0.55)\n  sx2.value = cos(elapsed * 0.66)\n  sy2.value = cos(elapsed * 0.77)\n  sz2.value = cos(elapsed * 0.88)\n\n  fit0.value.update()\n  fit1.value.update()\n  fit2.value.update()\n})\n</script>\n\n<template>\n  <TresPerspectiveCamera :position=\"[5, 5, 5]\" />\n  <TresGroup\n    :rotation=\"[rx0, ry0, rz0]\"\n    :position=\"[x0, y0, z0]\"\n    :scale=\"[sx0, sy0, sz0]\"\n  >\n    <TresGroup\n      :rotation=\"[rx1, ry1, rz1]\"\n      :position=\"[x1, y1, z1]\"\n      :scale=\"[sx1, sy1, sz1]\"\n    >\n      <TresGroup\n        :rotation=\"[-1, 0, 0]\"\n        :visible=\"choice.value === object\"\n      >\n        <primitive :object=\"object\" />\n      </TresGroup>\n      <TresGroup\n        :rotation=\"[rx2, ry2, rz2]\"\n        :position=\"[x2, y2, z2]\"\n        :scale=\"[sx2, sy2, sz2]\"\n      >\n        <Fit\n          ref=\"fit0\"\n          :into=\"choice.value\"\n        >\n          <TresMesh\n            v-for=\"(p, ii) of getPositions(0)\"\n            :key=\"ii\"\n            :position=\"p\"\n          >\n            <TresBoxGeometry />\n            <TresMeshBasicMaterial color=\"red\" />\n          </TresMesh>\n        </Fit>\n      </TresGroup>\n    </TresGroup>\n  </TresGroup>\n  <Fit\n    ref=\"fit1\"\n    :into=\"choice.value\"\n  >\n    <TresMesh :position=\"[x3, y3, 3]\">\n      <TresTorusGeometry />\n      <TresMeshBasicMaterial color=\"blue\" />\n    </TresMesh>\n    <TresMesh :position=\"[x3, y3, 0]\">\n      <TresTorusGeometry />\n      <TresMeshBasicMaterial color=\"blue\" />\n    </TresMesh>\n    <TresMesh :position=\"[x3, y3, -3]\">\n      <TresTorusGeometry />\n      <TresMeshBasicMaterial color=\"blue\" />\n    </TresMesh>\n  </Fit>\n  <Fit\n    ref=\"fit2\"\n    :into=\"choice.value\"\n  >\n    <TresMesh :position=\"[0, 0, -5]\">\n      <TresSphereGeometry />\n      <TresMeshBasicMaterial color=\"green\" />\n    </TresMesh>\n  </Fit>\n  <OrbitControls />\n  <TresGridHelper />\n</template>\n"
  },
  {
    "path": "playground/vue/src/pages/staging/fit/index.vue",
    "content": "<script setup lang=\"ts\">\nimport { TresCanvas } from '@tresjs/core'\nimport { Box3, BoxGeometry, Mesh, MeshBasicMaterial, Vector3 } from 'three'\nimport { useState } from '../../../composables/state'\nimport TheExperience from './FitDemo.vue'\n\n// NOTE: Make choices for `:into` options\n// radio buttons.\nconst object = new Mesh(new BoxGeometry(), new MeshBasicMaterial({ wireframe: true }))\n\nconst choices = [\n  { label: 'Turn off' },\n  { label: 'null', value: null },\n  { label: 'Default – fit into 1 x 1 x 1 box at world origin' },\n  { label: 'undefined', value: undefined },\n  { label: 'Scale' },\n  { label: 'Number', value: 1 },\n  { label: 'Number', value: 2 },\n  { label: 'Number', value: 3 },\n  { label: 'Array', value: [1, 1, 1] as [number, number, number] },\n  { label: 'Array', value: [1, 2, 3] as [number, number, number] },\n  { label: 'Array', value: [3, 2, 1] as [number, number, number] },\n  { label: 'Array', value: [5, 6, 7] as [number, number, number] },\n  { label: 'Array', value: [7, 7, 7] as [number, number, number] },\n  { label: 'Vector3', value: new Vector3(1, 1, 1) },\n  { label: 'Vector3', value: new Vector3(1, 2, 3) },\n  { label: 'Vector3', value: new Vector3(3, 2, 1) },\n  { label: 'Scale and position' },\n  { label: 'Box3(0,0,0, 1,1,1)', value: new Box3(new Vector3(0, 0, 0), new Vector3(1, 1, 1)) },\n  { label: 'Box3(-1,-1,-1, 1,1,1)', value: new Box3(new Vector3(-1, -1, -1), new Vector3(1, 1, 1)) },\n  { label: 'Box3(-5,0,-5, 5,10,5)', value: new Box3(new Vector3(-5, 0, -5), new Vector3(5, 10, 5)) },\n  { label: 'Object', value: object },\n]\nconst choice = shallowRef(choices[1])\n\nconst { renderingTimes } = useState()\n\nfunction onRender() {\n  renderingTimes.value = 1\n}\n</script>\n\n<template>\n  <div class=\"overlay\">\n    <h2><code>:into</code> value</h2>\n    <template\n      v-for=\"c, i of choices\"\n      :key=\"i\"\n    >\n      <div>\n        <div v-if=\"'value' in c\">\n          <input\n            :id=\"`id-${i}`\"\n            :checked=\"c === choice\"\n            type=\"radio\"\n            value=\"c.label\"\n            name=\"choice\"\n            @change=\"() => { choice = c; }\"\n          />\n          <label :for=\"`id-${i}`\">{{ `${c.label} - ${JSON.stringify(c.value)?.substring(0, 25)}` }}</label>\n        </div>\n        <h2 v-else>\n          {{ c.label }}\n        </h2>\n      </div>\n    </template>\n    <p>N.B.: <code>fit.update()</code> is called continuously in the update loop.</p>\n  </div>\n  <GraphPane />\n  <TresCanvas render-mode=\"on-demand\" @render=\"onRender\">\n    <TheExperience :object=\"object\" :choice=\"choice\" />\n  </TresCanvas>\n</template>\n\n<style scoped>\n.overlay {\n  z-index: 2;\n  position: fixed;\n  width: 240px;\n  padding: 10px;\n  margin: 5px;\n  font-family: sans-serif;\n  font-size: 10px;\n  background-color: white;\n  border-radius: 5px;\n}\n</style>\n"
  },
  {
    "path": "playground/vue/src/router/index.ts",
    "content": "import { createRouter, createWebHistory } from 'vue-router'\nimport {\n  abstractionsRoutes,\n  controlsRoutes,\n  loadersRoutes,\n  materialsRoutes,\n  miscRoutes,\n  shapesRoutes,\n  stagingRoutes,\n} from './routes'\n\nconst routes = [\n  {\n    path: '/',\n    name: 'Home',\n    component: () => import('../pages/index.vue'),\n  },\n  ...abstractionsRoutes,\n  ...controlsRoutes,\n  ...stagingRoutes,\n  ...loadersRoutes,\n  ...materialsRoutes,\n  ...miscRoutes,\n  ...shapesRoutes,\n  ...miscRoutes,\n]\n\nexport const router = createRouter({\n  history: createWebHistory(),\n  routes,\n})\n"
  },
  {
    "path": "playground/vue/src/router/routes/abstractions.ts",
    "content": "export const abstractionsRoutes = [\n  {\n    path: '/abstractions/levioso',\n    name: 'Levioso',\n    component: () => import('../../pages/abstractions/LeviosoDemo.vue'),\n  },\n  {\n    path: '/abstractions/text-3d',\n    name: 'Text3D',\n    component: () => import('../../pages/abstractions/Text3DDemo.vue'),\n  },\n  {\n    path: '/abstractions/mouse-parallax',\n    name: 'MouseParallax',\n    component: () => import('../../pages/abstractions/MouseParallaxDemo.vue'),\n  },\n  {\n    path: '/abstractions/lensflare',\n    name: 'Lensflare',\n    component: () => import('../../pages/abstractions/lensflare/index.vue'),\n  },\n  {\n    path: '/abstractions/reflector-mesh',\n    name: 'ReflectorMeshDemo',\n    component: () => import('../../pages/abstractions/ReflectorMeshDemo.vue'),\n  },\n  {\n    path: '/abstractions/global-audio',\n    name: 'GlobalAudio',\n    component: () => import('../../pages/abstractions/GlobalAudioDemo.vue'),\n  },\n  {\n    path: '/abstractions/fbo',\n    name: 'Fbo',\n    component: () => import('../../pages/abstractions/fbo/index.vue'),\n  },\n  {\n    path: '/abstractions/use-fbo',\n    name: 'useFbo',\n    component: () => import('../../pages/abstractions/fbo/useFBODemo.vue'),\n  },\n  {\n    path: '/abstractions/use-surface-sampler',\n    name: 'useSampler',\n    component: () => import('../../pages/abstractions/useSurfaceSampler.vue'),\n  },\n  {\n    path: '/abstractions/sampler',\n    name: 'Sampler',\n    component: () => import('../../pages/abstractions/Sampler.vue'),\n  },\n  {\n    path: '/abstractions/edges',\n    name: 'Edges',\n    component: () => import('../../pages/abstractions/EdgesDemo.vue'),\n  },\n  {\n    path: '/abstractions/positional-audio',\n    name: 'PositionalAudio',\n    component: () => import('../../pages/abstractions/PositionalAudioDemo.vue'),\n  },\n  {\n    path: '/abstractions/animated-sprite',\n    name: 'AnimatedSprite',\n    component: () => import('../../pages/abstractions/AnimatedSpriteDemo.vue'),\n  },\n  {\n    path: '/abstractions/marching-cubes',\n    name: 'MarchingCubes',\n    component: () => import('../../pages/abstractions/MarchingCubesDemo.vue'),\n  },\n  {\n    path: '/abstractions/mask',\n    name: 'Mask',\n    component: () => import('../../pages/abstractions/MaskDemo.vue'),\n  },\n  {\n    path: '/abstractions/cube-camera',\n    name: 'CubeCamera',\n    component: () => import('../../pages/abstractions/CubeCameraDemo.vue'),\n  },\n  {\n    path: '/abstractions/gradient-texture',\n    name: 'GradientTexture',\n    component: () => import('../../pages/abstractions/GradientTextureDemo.vue'),\n  },\n  {\n    path: '/abstractions/screen-space',\n    name: 'ScreenSpace',\n    component: () => import('../../pages/abstractions/ScreenSpaceDemo.vue'),\n  },\n  {\n    path: '/abstractions/outline',\n    name: 'Outline',\n    component: () => import('../../pages/abstractions/OutlineDemo.vue'),\n  },\n  {\n    path: '/abstractions/image',\n    name: 'Image',\n    component: () => import('../../pages/abstractions/ImageDemo.vue'),\n  },\n  {\n    path: '/abstractions/billboard',\n    name: 'Billboard',\n    component: () => import('../../pages/abstractions/BillboardDemo.vue'),\n  },\n  {\n    path: '/abstractions/screen-sizer',\n    name: 'ScreenSizer',\n    component: () => import('../../pages/abstractions/ScreenSizerDemo.vue'),\n  },\n  {\n    path: '/abstractions/use-animations',\n    name: 'useAnimations',\n    component: () => import('../../pages/abstractions/use-animations/index.vue'),\n  },\n]\n"
  },
  {
    "path": "playground/vue/src/router/routes/controls.ts",
    "content": "export const controlsRoutes = [\n  {\n    path: '/controls/orbit-controls',\n    name: 'OrbitControls',\n    component: () => import('../../pages/controls/OrbitControlsDemo.vue'),\n  },\n  {\n    path: '/controls/camera-controls',\n    name: 'CameraControls',\n    component: () => import('../../pages/controls/CameraControlsDemo.vue'),\n  },\n  {\n    path: '/controls/map-controls',\n    name: 'MapControls',\n    component: () => import('../../pages/controls/MapControlsDemo.vue'),\n  },\n  {\n    path: '/controls/transform-controls',\n    name: 'TransformControls',\n    component: () => import('../../pages/controls/TransformControlsDemo.vue'),\n  },\n  {\n    path: '/controls/keyboard-controls',\n    name: 'KeyboardControls',\n    component: () => import('../../pages/controls/KeyboardControlsDemo.vue'),\n  },\n  {\n    path: '/controls/pointerlock-controls',\n    name: 'PointerLockControls',\n    component: () => import('../../pages/controls/PointerLockControlsDemo.vue'),\n  },\n  {\n    path: '/controls/scroll-controls',\n    name: 'ScrollControls',\n    component: () => import('../../pages/controls/ScrollControlsDemo.vue'),\n  },\n  {\n    path: '/controls/helper',\n    name: 'Helper',\n    component: () => import('../../pages/controls/HelperDemo.vue'),\n  },\n]\n"
  },
  {
    "path": "playground/vue/src/router/routes/index.ts",
    "content": "import { abstractionsRoutes } from './abstractions'\nimport { controlsRoutes } from './controls'\nimport { loadersRoutes } from './loaders'\nimport { materialsRoutes } from './materials'\nimport { miscRoutes } from './misc'\nimport { shapesRoutes } from './shapes'\nimport { stagingRoutes } from './staging'\n\nexport {\n  abstractionsRoutes,\n  controlsRoutes,\n  loadersRoutes,\n  materialsRoutes,\n  miscRoutes,\n  shapesRoutes,\n  stagingRoutes,\n}\n"
  },
  {
    "path": "playground/vue/src/router/routes/loaders.ts",
    "content": "export const loadersRoutes = [\n  {\n    path: '/loaders/use-gltf',\n    name: 'useGLTF',\n    component: () => import('../../pages/loaders/use-gltf/index.vue'),\n  },\n  {\n    path: '/loaders/gltf-model',\n    name: 'GLTFModel',\n    component: () => import('../../pages/loaders/use-gltf/GLTFModelDemo.vue'),\n  },\n  {\n    path: '/loaders/use-svg',\n    name: 'useSVG',\n    component: () => import('../../pages/loaders/use-svg/index.vue'),\n  },\n  {\n    path: '/loaders/use-svg-component',\n    name: 'useSVGComponent',\n    component: () => import('../../pages/loaders/use-svg/SVGModelDemo.vue'),\n  },\n  {\n    path: '/loaders/use-texture',\n    name: 'useTexture',\n    component: () => import('../../pages/loaders/use-texture/index.vue'),\n  },\n  {\n    path: '/loaders/use-texture-component',\n    name: 'UseTexture',\n    component: () => import('../../pages/loaders/use-texture/UseTextureComponent.vue'),\n  },\n  {\n    path: '/loaders/use-fbx',\n    name: 'useFBX',\n    component: () => import('../../pages/loaders/use-fbx/index.vue'),\n  },\n  {\n    path: '/loaders/fbx-model',\n    name: 'FBXModel',\n    component: () => import('../../pages/loaders/use-fbx/FBXModelDemo.vue'),\n  },\n  {\n    path: '/loaders/use-video-texture',\n    name: 'useVideoTexture',\n    component: () => import('../../pages/loaders/useVideoTextureDemo.vue'),\n  },\n  {\n    path: '/loaders/pbr-textures',\n    name: 'PBRTextures',\n    component: () => import('../../pages/loaders/use-texture/PBRTextures.vue'),\n  },\n]\n"
  },
  {
    "path": "playground/vue/src/router/routes/materials.ts",
    "content": "export const materialsRoutes = [\n  {\n    path: '/materials/wobble-material',\n    name: 'WobbleMaterial',\n    component: () => import('../../pages/materials/WobbleMaterialDemo.vue'),\n  },\n  {\n    path: '/materials/glass-material',\n    name: 'GlassMaterial',\n    component: () => import('../../pages/materials/GlassMaterialDemo.vue'),\n  },\n  {\n    path: '/materials/custom-shader-material',\n    name: 'CustomShaderMaterial',\n    component: () => import('../../pages/materials/CustomShaderMaterialDemo.vue'),\n  },\n  {\n    path: '/materials/reflection-material',\n    name: 'ReflectionMaterial',\n    component: () => import('../../pages/materials/MeshReflectionMaterialDemo.vue'),\n  },\n  {\n    path: '/materials/holographic-material',\n    name: 'HolographicMaterial',\n    component: () => import('../../pages/materials/HolographicMaterialDemo.vue'),\n  },\n  {\n    path: '/materials/point-material',\n    name: 'PointMaterial',\n    component: () => import('../../pages/materials/PointMaterialDemo.vue'),\n  },\n  {\n    path: '/materials/discard-material',\n    name: 'MeshDiscardMaterial',\n    component: () => import('../../pages/materials/MeshDiscardMaterialDemo.vue'),\n  },\n]\n"
  },
  {
    "path": "playground/vue/src/router/routes/misc.ts",
    "content": "export const miscRoutes = [\n  {\n    path: '/misc/lod',\n    name: 'LOD',\n    component: () => import('../../pages/misc/LODDemo.vue'),\n  },\n  {\n    path: '/misc/html',\n    name: 'HTML',\n    component: () => import('../../pages/misc/HTMLDemo.vue'),\n  },\n  {\n    path: '/misc/laptop',\n    name: 'Laptop',\n    component: () => import('../../pages/misc/LaptopDemo.vue'),\n  },\n  {\n    path: '/misc/stats-gl',\n    name: 'StatsGl',\n    component: () => import('../../pages/misc/StatsGlDemo.vue'),\n  },\n  {\n    path: '/misc/stats',\n    name: 'Stats',\n    component: () => import('../../pages/misc/StatsDemo.vue'),\n  },\n  {\n    path: '/misc/bake-shadows',\n    name: 'BakeShadows',\n    component: () => import('../../pages/misc/BakeShadowsDemo.vue'),\n  },\n  {\n    path: '/misc/gltfExporter',\n    name: 'GLTFExporter',\n    component: () => import('../../pages/misc/GLTFExporterDemo.vue'),\n  },\n  {\n    path: '/misc/useIntersect',\n    name: 'useIntersect',\n    component: () => import('../../pages/misc/useIntersect/index.vue'),\n  },\n]\n"
  },
  {
    "path": "playground/vue/src/router/routes/shapes.ts",
    "content": "export const shapesRoutes = [\n  {\n    path: '/shapes/catmullromcurve3',\n    name: 'CatmullRomCurve3',\n    component: () => import('../../pages/shapes/CatmullRomCurve3Demo.vue'),\n  },\n  {\n    path: '/shapes/quadratic-bezier-line',\n    name: 'QuadraticBezierLine',\n    component: () => import('../../pages/shapes/QuadraticBezierLineDemo.vue'),\n  },\n  {\n    path: '/shapes/cubic-bezier-line',\n    name: 'CubicBezierLine',\n    component: () => import('../../pages/shapes/CubicBezierLineDemo.vue'),\n  },\n  {\n    path: '/shapes/cylinder',\n    name: 'Cylinder',\n    component: () => import('../../pages/shapes/Cylinder.vue'),\n  },\n  {\n    path: '/shapes/line2',\n    name: 'Line2',\n    component: () => import('../../pages/shapes/Line2Demo.vue'),\n  },\n  {\n    path: '/shapes/superformula',\n    name: 'Superformula',\n    component: () => import('../../pages/shapes/SuperformulaDemo.vue'),\n  },\n  {\n    path: '/shapes/roundedbox',\n    name: 'RoundedBox',\n    component: () => import('../../pages/shapes/RoundedBoxDemo.vue'),\n  },\n  {\n    path: '/shapes/screenQuad',\n    name: 'ScreenQuad',\n    component: () => import('../../pages/shapes/ScreenQuadDemo.vue'),\n  },\n  {\n    path: '/shapes/on-demand-shapes',\n    name: 'on-demand Shapes',\n    component: () => import('../../pages/shapes/OnDemandShapesDemo.vue'),\n  },\n]\n"
  },
  {
    "path": "playground/vue/src/router/routes/staging.ts",
    "content": "export const stagingRoutes = [\n  {\n    path: '/staging/smoke',\n    name: 'Smoke',\n    component: () => import('../../pages/staging/SmokeDemo.vue'),\n  },\n  {\n    path: '/staging/precipitation',\n    name: 'Precipitation',\n    component: () => import('../../pages/staging/PrecipitationDemo.vue'),\n  },\n  {\n    path: '/staging/stars',\n    name: 'Stars',\n    component: () => import('../../pages/staging/StarsDemo.vue'),\n  },\n  {\n    path: '/staging/environment',\n    name: 'Environment',\n    component: () => import('../../pages/staging/environment/EnvironmentDemo.vue'),\n  },\n  {\n    path: '/staging/backdrop',\n    name: 'Backdrop',\n    component: () => import('../../pages/staging/CircleShadowDemo.vue'),\n  },\n  {\n    path: '/staging/contact-shadows',\n    name: 'ContactShadows',\n    component: () => import('../../pages/staging/ContactShadowsDemo.vue'),\n  },\n  {\n    path: '/staging/sky',\n    name: 'Sky',\n    component: () => import('../../pages/staging/SkyDemo.vue'),\n  },\n  {\n    path: '/staging/sparkles',\n    name: 'Sparkles',\n    component: () => import('../../pages/staging/SparklesDemo.vue'),\n  },\n  {\n    path: '/staging/ocean',\n    name: 'Ocean',\n    component: () => import('../../pages/staging/OceanDemo.vue'),\n  },\n  {\n    path: '/staging/bounds',\n    name: 'Bounds',\n    component: () => import('../../pages/staging/BoundsDemo.vue'),\n  },\n  {\n    path: '/staging/fit',\n    name: 'Fit',\n    component: () => import('../../pages/staging/fit/index.vue'),\n  },\n  {\n    path: '/staging/align',\n    name: 'Align',\n    component: () => import('../../pages/staging/AlignDemo.vue'),\n  },\n  {\n    path: '/staging/soft-shadows',\n    name: 'SoftShadows',\n    component: () => import('../../pages/staging/SoftShadowsDemo.vue'),\n  },\n  {\n    path: '/staging/grid',\n    name: 'Grid',\n    component: () => import('../../pages/staging/GridDemo.vue'),\n  },\n  {\n    path: '/staging/circle-shadow',\n    name: 'CircleShadow',\n    component: () => import('../../pages/staging/CircleShadowDemo.vue'),\n  },\n  {\n    path: '/staging/accumulative-shadows',\n    name: 'Accumulative Shadows',\n    component: () => import('../../pages/staging/AccumulativeShadowsDemo.vue'),\n  },\n  {\n    path: '/staging/stage',\n    name: 'Stage',\n    component: () => import('../../pages/staging/StageDemo.vue'),\n  },\n]\n"
  },
  {
    "path": "playground/vue/src/style.css",
    "content": "html,\nbody {\n  margin: 0;\n  padding: 0;\n  height: 100%;\n  width: 100%;\n}\nbody.Home {\n  margin: 0;\n  padding: 0;\n  height: auto;\n  width: auto;\n}\n#app {\n  height: 100%;\n  width: 100%;\n}\n"
  },
  {
    "path": "playground/vue/src/vite-env.d.ts",
    "content": "/// <reference types=\"vite/client\" />\n"
  },
  {
    "path": "playground/vue/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"ESNext\",\n    \"jsx\": \"preserve\",\n    \"lib\": [\"ESNext\", \"DOM\"],\n    \"useDefineForClassFields\": true,\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"bundler\",\n    \"paths\": {\n      \"@tresjs/cientos\": [\"../../src/index.ts\"]\n    },\n    \"resolveJsonModule\": true,\n    \"strict\": true,\n    \"noEmit\": true,\n    \"esModuleInterop\": true,\n    \"isolatedModules\": true,\n    \"skipLibCheck\": true\n  },\n  \"references\": [{ \"path\": \"./tsconfig.node.json\" }],\n  \"include\": [\"src/**/*.ts\", \"src/**/*.d.ts\", \"src/**/*.tsx\", \"src/**/*.vue\", \"auto-imports.d.ts\", \"components.d.ts\"]\n}\n"
  },
  {
    "path": "playground/vue/tsconfig.node.json",
    "content": "{\n  \"compilerOptions\": {\n    \"composite\": true,\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"Node\",\n    \"allowSyntheticDefaultImports\": true\n  },\n  \"include\": [\"vite.config.ts\"]\n}\n"
  },
  {
    "path": "playground/vue/vite.config.ts",
    "content": "import { templateCompilerOptions } from '@tresjs/core'\nimport vue from '@vitejs/plugin-vue'\nimport { resolve } from 'pathe'\nimport UnoCSS from 'unocss/vite'\nimport AutoImport from 'unplugin-auto-import/vite'\nimport Components from 'unplugin-vue-components/vite'\nimport { defineConfig } from 'vite'\nimport glsl from 'vite-plugin-glsl'\nimport { qrcode } from 'vite-plugin-qrcode'\n\n// https://vitejs.dev/config/\nexport default defineConfig({\n  plugins: [\n    glsl(),\n    vue(templateCompilerOptions),\n    AutoImport({\n      dts: true,\n      eslintrc: {\n        enabled: true, // <-- this\n      },\n      imports: ['vue'],\n    }),\n    Components({\n      /* options */\n    }),\n    UnoCSS({\n      theme: {\n        colors: {\n          'cientos-blue': '#82dbc5',\n          'cientos-orange': '#fbb03b',\n        },\n      },\n    }),\n    qrcode(),\n  ],\n  resolve: {\n    alias: {\n      '@tresjs/cientos': resolve(__dirname, '../../src/'),\n    },\n  },\n})\n"
  },
  {
    "path": "pnpm-workspace.yaml",
    "content": "packages:\n  - docs\n  - playground/*\n"
  },
  {
    "path": "renovate.json",
    "content": "{\n  \"$schema\": \"https://docs.renovatebot.com/renovate-schema.json\",\n  \"extends\": [\n    \"config:base\"\n  ],\n  \"packageRules\": [\n    {\n      \"matchUpdateTypes\": [\"minor\", \"patch\"],\n      \"matchCurrentVersion\": \"!/^0/\",\n      \"automerge\": true,\n      \"automergeType\": \"branch\"\n    }\n  ]\n}\n"
  },
  {
    "path": "src/core/abstractions/AnimatedSprite/Atlas.ts",
    "content": "import { logError } from '@tresjs/core'\nimport { type Texture, TextureLoader } from 'three'\nimport { expand } from './AtlasAnimationDefinitionParser'\nimport { getNumbersFromEnd, stripUnderscoresNumbersFromEnd } from './StringOps'\n\nexport async function getTextureAndAtlasAsync(\n  imagePathOrImageData: string,\n  atlasPathOrAtlasish: string | Atlasish,\n): Promise<[Texture | Texture[], Atlas]> {\n  // Use plain Three.js TextureLoader for loading the texture\n  const loader = new TextureLoader()\n  const texturePromise = new Promise<Texture>((resolve, reject) => {\n    loader.load(\n      imagePathOrImageData,\n      resolve,\n      undefined,\n      reject,\n    )\n  })\n\n  const atlasishPromise: Promise<Atlasish>\n    = typeof atlasPathOrAtlasish !== 'string'\n      ? new Promise(resolve => resolve(atlasPathOrAtlasish as Atlasish))\n      : fetch(atlasPathOrAtlasish)\n          .then(response => response.json())\n          .catch(e => logError(`Cientos Atlas - ${e}`))\n\n  return Promise.all([texturePromise, atlasishPromise]).then(\n    ([texture, atlasish]) => {\n      const atlas = getAtlas(\n        atlasish,\n        texture.image.width,\n        texture.image.height,\n      )\n      return [texture, atlas]\n    },\n  )\n}\n\nexport interface AtlasFrame {\n  name: string\n  width: number\n  height: number\n  offsetX: number\n  offsetY: number\n  repeatX: number\n  repeatY: number\n}\n\nexport interface Atlas {\n  frames: AtlasFrame[]\n  animations: Record<string, AtlasFrame[]>\n}\n\nexport function getAtlas(\n  atlasish: Atlasish,\n  textureWidth: number,\n  textureHeight: number,\n): Atlas {\n  const frames\n    = typeof atlasish === 'number' || Array.isArray(atlasish)\n      ? getAtlasFramesFromNumColsNumRows(atlasish, textureWidth, textureHeight)\n      : getAtlasFramesFromTexturePackerData(\n          atlasish,\n          textureWidth,\n          textureHeight,\n        )\n\n  return { frames, animations: groupAtlasFramesByKey(frames) }\n}\n\nexport function getAtlasFrames(\n  atlas: Atlas,\n  animationNameOrFrameNumber: string | number | [number, number],\n  reversed: boolean,\n): AtlasFrame[] {\n  let frames: AtlasFrame[]\n  if (typeof animationNameOrFrameNumber === 'string') { frames = getAtlasFramesByAnimationName(atlas, animationNameOrFrameNumber) }\n  else if (typeof animationNameOrFrameNumber === 'number') {\n    frames = getAtlasFramesByIndices(\n      atlas,\n      animationNameOrFrameNumber,\n      animationNameOrFrameNumber,\n    )\n  }\n  else {\n    frames = getAtlasFramesByIndices(\n      atlas,\n      animationNameOrFrameNumber[0],\n      animationNameOrFrameNumber[1],\n    )\n  }\n  return reversed ? frames.toReversed() : frames\n}\n\nexport function getNullAtlasFrame(): AtlasFrame {\n  return {\n    name: 'null',\n    width: 0,\n    height: 0,\n    offsetX: 0,\n    offsetY: 0,\n    repeatX: 0,\n    repeatY: 0,\n  }\n}\n\nexport type AtlasData =\n  | TexturePackerFrameDataArray\n  | TexturePackerFrameDataObject\nexport type Atlasish = AtlasData | [number, number] | number\n\ninterface TexturePackerFrameData {\n  filename: string\n  frame: { x: number, y: number, w: number, h: number }\n}\n\ninterface TexturePackerFrameDataArray {\n  frames: TexturePackerFrameData[]\n}\n\ninterface TexturePackerFrameDataObject {\n  frames: Record<string, TexturePackerFrameData>\n}\n\nfunction getAtlasFramesFromTexturePackerData(\n  data: TexturePackerFrameDataArray | TexturePackerFrameDataObject,\n  width: number,\n  height: number,\n) {\n  return Array.isArray(data.frames)\n    ? getAtlasFramesFromTexturePackerDataArray(\n        data as TexturePackerFrameDataArray,\n        width,\n        height,\n      )\n    : getAtlasFramesFromTexturePackerDataObject(\n        data as TexturePackerFrameDataObject,\n        width,\n        height,\n      )\n}\n\nfunction getAtlasFramesFromTexturePackerDataArray(\n  data: TexturePackerFrameDataArray,\n  width: number,\n  height: number,\n): AtlasFrame[] {\n  const invWidth = 1 / width\n  const invHeight = 1 / height\n  return data.frames.map(d => ({\n    name: d.filename,\n    offsetX: d.frame.x * invWidth,\n    offsetY: 1 - (d.frame.y + d.frame.h) * invHeight,\n    repeatX: d.frame.w * invWidth,\n    repeatY: d.frame.h * invHeight,\n    width: d.frame.w,\n    height: d.frame.h,\n  }))\n}\n\nfunction getAtlasFramesFromTexturePackerDataObject(\n  data: TexturePackerFrameDataObject,\n  width: number,\n  height: number,\n): AtlasFrame[] {\n  const invWidth = 1 / width\n  const invHeight = 1 / height\n  return Object.entries(data.frames).map(([k, v]) => ({\n    name: k,\n    offsetX: v.frame.x * invWidth,\n    offsetY: 1 - (v.frame.y + v.frame.h) * invHeight,\n    repeatX: v.frame.w * invWidth,\n    repeatY: v.frame.h * invHeight,\n    width: v.frame.w,\n    height: v.frame.h,\n  }))\n}\n\nfunction getAtlasFramesFromNumColsNumRows(\n  numColsOrNumColsNumRows: number | [number, number],\n  width: number,\n  height: number,\n  name = 'default',\n): AtlasFrame[] {\n  const [numCols, numRows] = Array.isArray(numColsOrNumColsNumRows)\n    ? numColsOrNumColsNumRows\n    : [numColsOrNumColsNumRows, 1]\n  const frameWidth = width / numCols\n  const frameHeight = height / numRows\n  const padAmount = (numCols * numRows).toString().length\n  const repeatX = 1 / numCols\n  const repeatY = 1 / numRows\n  const result: AtlasFrame[] = []\n\n  let i = 0\n  for (let row = numRows - 1; row >= 0; row--) {\n    for (let col = 0; col < numCols; col++) {\n      i++\n      result.push({\n        name: name + String(i).padStart(padAmount, '0'),\n        offsetX: col * repeatX,\n        offsetY: row * repeatY,\n        repeatX,\n        repeatY,\n        width: frameWidth,\n        height: frameHeight,\n      })\n    }\n  }\n  return result\n}\n\nexport function setAtlasDefinitions(atlas: Atlas, definitions: Record<string, string> = {}) {\n  const animations = groupAtlasFramesByKey(atlas.frames)\n  for (const [animationName, definitionStr] of Object.entries(definitions)) {\n    const frames: AtlasFrame[] = getAtlasFrames(atlas, animationName, false)\n    const expandedFrameIndices = expand(definitionStr)\n    for (const frameIndex of expandedFrameIndices) {\n      if (frameIndex < 0 || frames.length <= frameIndex) {\n        logError(\n          'Cientos Atlas: Attempting to access frame index '\n          + `${frameIndex} in animation ${animationName}, but it does not exist.`,\n        )\n      }\n    }\n    animations[animationName] = expandedFrameIndices.map(frameIndex => frames[frameIndex])\n  }\n  atlas.animations = animations\n}\n\nfunction getAtlasFramesByAnimationName(\n  atlas: Atlas,\n  name: string,\n): AtlasFrame[] {\n  if (!(name in atlas.animations)) {\n    const animationsMsg = Object.keys(atlas.animations)\n      .map(n => `* ${n}\\n`)\n      .join('')\n    logError(\n      `Cientos Atlas: getAtlasFramesByAnimationName\nThe animation name \"${name}\" does not exist in this atlas.\nAvailable names:\n${animationsMsg}`,\n    )\n    return [getNullAtlasFrame()]\n  }\n  return atlas.animations[name]\n}\n\nfunction getAtlasFramesByIndices(\n  atlas: Atlas,\n  startI: number,\n  endI: number,\n): AtlasFrame[] {\n  if (\n    startI < 0\n    || atlas.frames.length <= startI\n    || endI < 0\n    || atlas.frames.length <= endI\n  ) {\n    logError(\n      `Cientos Atlas: getFramesByIndex – [${startI}, ${endI}] is out of bounds.`,\n    )\n    return [getNullAtlasFrame()]\n  }\n  const result = []\n  const sign = Math.sign(endI - startI)\n  if (sign === 0) { return [atlas.frames[startI]] }\n  for (let i = startI; i !== endI + sign; i += sign) {\n    result.push(atlas.frames[i])\n  }\n  return result\n}\n\n/**\n * @returns An object where all AtlasFrames with the same key are grouped in an ordered array by name in ascending value.\n * A key is defined as an alphanumeric string preceding a trailing numeric string.\n * E.g.:\n * \"hero0Idle\" has no key as it does not have trailing numeric string.\n * \"heroIdle0\" has the key \"heroIdle\".\n * @example ```\n * groupFramesByKey([{name: hero, ...}, {name: heroJump3, ...}, {name: heroJump0, ...}, {name: heroIdle0, ...}, {name: heroIdle1, ...}]) returns\n * {\n * heroJump: [{name: heroJump0, ...}, {name: heroJump3, ...}],\n * heroIdle: [{name: heroIdle0, ...}, {name: heroIdle1, ...}]\n * }\n * ```\n */\nfunction groupAtlasFramesByKey(\n  frames: AtlasFrame[],\n): Record<string, AtlasFrame[]> {\n  const result: Record<string, AtlasFrame[]> = {}\n\n  for (const frame of frames) {\n    if (getNumbersFromEnd(frame.name) !== null) {\n      const key = stripUnderscoresNumbersFromEnd(frame.name)\n      if (Object.prototype.hasOwnProperty.call(result, key)) {\n        result[key].push(frame)\n      }\n      else {\n        result[key] = [frame]\n      }\n    }\n  }\n\n  for (const entry of Object.values(result)) {\n    entry.sort((a, b) => a.name.localeCompare(b.name))\n  }\n\n  return result\n}\n"
  },
  {
    "path": "src/core/abstractions/AnimatedSprite/AtlasAnimationDefinitionParser.ts",
    "content": "import { logError } from '@tresjs/core'\n\n/**\n * Expand an animation definition string into an array of numbers.\n * @param definitionStr - A comma-separated string of frame numbers with optional parentheses-surrounded durations.\n * @example - expand(\"0,2\") === [0,2]\n * @example - expand(\"2(10)\") === [2,2,2,2,2,2,2,2,2,2]\n * @example - expand(\"1-4\") === [1,2,3,4]\n * @example - expand(\"10-5(2)\") === [10,10,9,9,8,8,7,7,6,6,5,5]\n * @example - expand(\"1-4(3),10(2)\") === [1,1,1,2,2,2,3,3,3,4,4,4,10,10]\n */\n\nexport function expand(definitionStr: string): number[] {\n  const parsed = parse(definitionStr)\n  const result: number[] = []\n  for (const { startFrame, endFrame, duration } of parsed) {\n    if (duration <= 0) {\n      continue\n    }\n    else if (endFrame < 0 || startFrame === endFrame) {\n      for (let _ = 0; _ < duration; _++) {\n        result.push(startFrame)\n      }\n      continue\n    }\n    else {\n      const sign = Math.sign(endFrame - startFrame)\n      for (\n        let frame = startFrame;\n        frame !== endFrame + sign;\n        frame += sign\n      ) {\n        for (let _ = 0; _ < duration; _++) {\n          result.push(frame)\n        }\n      }\n    }\n  }\n  return result\n}\n\ninterface AnimationDefinition {\n  startFrame: number\n  endFrame: number\n  duration: number\n}\n\n/**\n * Parse an animation defintion string into an array of AnimationDefinition.\n * @param definitionStr - A comma-separated string of frame numbers with optional parentheses-surrounded durations.\n * @example - parse(\"0,2\") === [{startFrame:0, endFrame:0, duration:1}, {startFrame:2, endFrame:2, duration:1}]\n * @example - parse(\"2(10)\") === [{startFrame:2, endFrame:2, duration:10}]\n * @example - parse(\"1-4\") === [{startFrame:1, endFrame:4, duration:1}]\n * @example - parse(\"10-5(2)\") === [{startFrame:10, endFrame:5, duration:2}]\n * @example - parse(\"1-4(3),10(2)\") === [{startFrame:1, endFrame:4, duration:3}, {startFrame:10, endFrame:10, duration:2}]\n */\n\nfunction parse(definitionStr: string): AnimationDefinition[] {\n  let transition: Transition = 'START_FRAME_IN'\n  const result: AnimationDefinition[] = []\n  for (const { name, value, startI } of tokenize(definitionStr)) {\n    if (transition === 'START_FRAME_IN') {\n      if (name === 'NUMBER') {\n        result.push({\n          startFrame: value,\n          endFrame: value,\n          duration: 1,\n        })\n        transition = 'START_FRAME_OUT'\n      }\n      else {\n        logDefinitionSyntaxError(\n          'number',\n          name,\n          definitionStr,\n          startI,\n        )\n      }\n    }\n    else if (transition === 'START_FRAME_OUT') {\n      if (name === 'COMMA') {\n        transition = 'START_FRAME_IN'\n      }\n      else if (name === 'HYPHEN') {\n        transition = 'END_FRAME_IN'\n      }\n      else if (name === 'OPEN_PAREN') {\n        transition = 'DURATION_IN'\n      }\n      else {\n        logDefinitionSyntaxError(\n          '\",\", \"-\", \"(\"',\n          name,\n          definitionStr,\n          startI,\n        )\n      }\n    }\n    else if (transition === 'END_FRAME_IN') {\n      if (name === 'NUMBER') {\n        result[result.length - 1].endFrame = value\n        transition = 'END_FRAME_OUT'\n      }\n      else {\n        logDefinitionSyntaxError(\n          'number',\n          name,\n          definitionStr,\n          startI,\n        )\n      }\n    }\n    else if (transition === 'END_FRAME_OUT') {\n      if (name === 'COMMA') {\n        transition = 'START_FRAME_IN'\n      }\n      else if (name === 'OPEN_PAREN') {\n        transition = 'DURATION_IN'\n      }\n      else {\n        logDefinitionSyntaxError(\n          '\\',\\' or \\'(\\'',\n          name,\n          definitionStr,\n          startI,\n        )\n      }\n    }\n    else if (transition === 'DURATION_IN') {\n      if (name === 'NUMBER') {\n        result[result.length - 1].duration = value\n        transition = 'DURATION_OUT'\n      }\n      else {\n        logDefinitionSyntaxError(\n          'number',\n          name,\n          definitionStr,\n          startI,\n        )\n      }\n    }\n    else if (transition === 'DURATION_OUT') {\n      if (name === 'CLOSE_PAREN') {\n        transition = 'NEXT_OR_DONE'\n      }\n      else {\n        logDefinitionSyntaxError('\"(\"', name, definitionStr, startI)\n      }\n    }\n    else if (transition === 'NEXT_OR_DONE') {\n      if (name === 'COMMA') {\n        transition = 'START_FRAME_IN'\n      }\n      else {\n        logDefinitionSyntaxError('\",\"', name, definitionStr, startI)\n      }\n    }\n  }\n\n  return result\n}\n\ntype Transition =\n  | 'START_FRAME_IN'\n  | 'START_FRAME_OUT'\n  | 'END_FRAME_IN'\n  | 'END_FRAME_OUT'\n  | 'DURATION_IN'\n  | 'DURATION_OUT'\n  | 'NEXT_OR_DONE'\n\ntype TokenName = 'COMMA' | 'HYPHEN' | 'OPEN_PAREN' | 'CLOSE_PAREN' | 'NUMBER'\ninterface Token {\n  name: TokenName\n  value: number\n  startI: number\n}\n\nfunction tokenize(definition: string): Token[] {\n  const result: Token[] = []\n  for (let ii = 0; ii < definition.length; ii++) {\n    const c = definition[ii]\n    if ('0123456789'.includes(c)) {\n      if (\n        result.length\n        && result[result.length - 1].name === 'NUMBER'\n      ) {\n        result[result.length - 1].value *= 10\n        result[result.length - 1].value += Number.parseInt(c)\n      }\n      else {\n        result.push({ name: 'NUMBER', value: Number.parseInt(c), startI: ii })\n      }\n    }\n    else if (c === ' ') {\n      continue\n    }\n    else if (c === ',') {\n      result.push({ name: 'COMMA', value: -1, startI: ii })\n    }\n    else if (c === '(') {\n      result.push({ name: 'OPEN_PAREN', value: -1, startI: ii })\n    }\n    else if (c === ')') {\n      result.push({ name: 'CLOSE_PAREN', value: -1, startI: ii })\n    }\n    else if (c === '-') {\n      result.push({ name: 'HYPHEN', value: -1, startI: ii })\n    }\n    else {\n      logDefinitionBadCharacter('0123456789,-()', c, definition, ii)\n    }\n  }\n\n  return result\n}\n\nfunction logDefinitionBadCharacter(\n  expected: string,\n  found: string,\n  definition: string,\n  index: number,\n) {\n  logError(\n    'Cientos AnimationDefinitionParser: '\n    + `Unexpected character while processing animation definition: expected ${expected}, got ${found}.\n${definition}\n${Array.from({ length: index + 1 }).join(' ')}^`,\n  )\n}\n\nfunction logDefinitionSyntaxError(\n  expected: string,\n  found: string,\n  definition: string,\n  index: number,\n) {\n  logError(\n    'Cientos AnimationDefinitionParser: '\n    + `Syntax error while processing animation definition: expected ${expected}, got ${found}.\n${definition}\n${Array.from({ length: index + 1 }).join(' ')}^`,\n  )\n}\n"
  },
  {
    "path": "src/core/abstractions/AnimatedSprite/StringOps.ts",
    "content": "const numbersAtEnd = /\\d*$/\nconst underscoresNumbersAtEnd = /_*\\d*$/\n\nexport function stripUnderscoresNumbersFromEnd(str: string) {\n  return str.replace(underscoresNumbersAtEnd, '')\n}\n\nexport function getNumbersFromEnd(str: string) {\n  const matches = str.match(numbersAtEnd)\n  if (matches) {\n    return Number.parseInt(matches[matches.length - 1])\n  }\n  return null\n}\n"
  },
  {
    "path": "src/core/abstractions/AnimatedSprite/component.vue",
    "content": "<script setup lang=\"ts\">\nimport { normalizeVectorFlexibleParam, useLoop, useTres } from '@tresjs/core'\nimport { DoubleSide } from 'three'\nimport { onUnmounted, ref, shallowRef, watch } from 'vue'\nimport type { TresVector2 } from '@tresjs/core'\nimport { getAtlasFrames, getNullAtlasFrame, getTextureAndAtlasAsync, setAtlasDefinitions } from './Atlas'\nimport type { Atlasish } from './Atlas'\n\nexport interface AnimatedSpriteProps {\n  /** URL of the image texture or an image dataURL. This prop is not reactive. */\n  image: string\n  /**\n   * If `string`, the URL of the JSON atlas.\n   * If `number`, the number of columns in the texture.\n   * If `[number, number]`, the number of columns/rows in the texture.\n   * If `AtlasData`, the atlas as a JS object.\n   * This prop is not reactive.\n   */\n  atlas: string | Atlasish\n  /**\n  * Specify playback frame order and repeated frames (delays). `definitions` is a record where keys are atlas animation names and values are strings containing an animation definition.\n  * A \"animation definition\" comma-separated string of frame numbers with optional parentheses-surrounded durations.\n  * Here is how various definition strings convert to arrays of frames for playback:\n  * \"0,2,1\" - [0,2,1], i.e., play frame 0, 2, then 1.\n  * \"2(10)\" - [2,2,2,2,2,2,2,2,2,2], i.e., play from 2 10 times.\n  * \"1-4\" - [1,2,3,4]\n  * \"10-5(2)\" - [10,10,9,9,8,8,7,7,6,6,5,5]\n  * \"1-4(3),10(2)\" - [1,1,1,2,2,2,3,3,3,4,4,4,10,10]\n   */\n  definitions?: Record<string, string>\n  /** Desired frames per second of the animation. */\n  fps?: number\n  /** Whether or not the animation should loop. */\n  loop?: boolean\n  /** If `string`, name of the animation to play. If `[number, number]`, start and end frames of the animation. If `number`, frame number to display. */\n  animation?: string | [number, number] | number\n  /** Whether the animation is paused. */\n  paused?: boolean\n  /** Whether to play the animation in reverse. */\n  reversed?: boolean\n  /** Whether the sprite should be flipped, left to right. */\n  flipX?: boolean\n  /** For a non-looping animation, when the animation ends, whether to display the zeroth frame. */\n  resetOnEnd?: boolean\n  /** Whether to display the object as a THREE.Sprite. [See THREE.Sprite](https://threejs.org/docs/?q=sprite#api/en/objects/Sprite) */\n  asSprite?: boolean\n  /** Anchor point of the object. A value of [0.5, 0.5] corresponds to the center. [0, 0] is left, bottom. */\n  center?: TresVector2\n  /** Alpha test value for the material. [See THREE.Material.alphaTest](https://threejs.org/docs/#api/en/materials/Material.alphaTest) */\n  alphaTest?: number\n  /** Depth test value for the material. [See THREE.Material.depthTest](https://threejs.org/docs/#api/en/materials/Material.depthTest) */\n  depthTest?: boolean\n  /** Depth write value for the material. [See THREE.Material.depthWrite](https://threejs.org/docs/#api/en/materials/Material.depthWrite) */\n  depthWrite?: boolean\n}\n\nconst props = withDefaults(defineProps<AnimatedSpriteProps>(), {\n  fps: 30,\n  loop: true,\n  animation: 0,\n  paused: false,\n  reversed: false,\n  flipX: false,\n  resetOnEnd: false,\n  asSprite: true,\n  center: () => [0.5, 0.5],\n  alphaTest: 0.0,\n  depthTest: true,\n  depthWrite: true,\n})\n\nconst emit = defineEmits<{\n  (e: 'frame', frameName: string): void\n  (e: 'end', frameName: string): void\n  (e: 'loop', frameName: string): void\n}>()\n\nconst { invalidate } = useTres()\n\nwatch(props, () => {\n  invalidate()\n})\n\nconst positionX = ref(0)\nconst positionY = ref(0)\nconst scaleX = ref(0)\nconst scaleY = ref(0)\n\nconst groupRef = shallowRef()\ndefineExpose({ instance: groupRef })\n\nconst [textureResult, atlas] = await getTextureAndAtlasAsync(props.image, props.atlas)\nconst texture = Array.isArray(textureResult) ? textureResult[0] : textureResult\ntexture.matrixAutoUpdate = false\n\nlet animation = getAtlasFrames(atlas, props.animation, props.reversed)\nlet centerX = 0.5\nlet centerY = 0.5\nlet cooldown = 1\nlet frame = getNullAtlasFrame()\nlet frameNameToEmit: string | null = null\nlet frameNum = 0\nlet frameHeldOnLoopEnd = false\nlet dirtyFlag = true\nconst TEXTURE_PX_TO_WORLD_UNITS = 0.01\n\nuseLoop().onBeforeRender(({ delta }) => {\n  if (!props.paused && !frameHeldOnLoopEnd) {\n    cooldown -= delta * props.fps\n  }\n\n  while (cooldown <= 0) {\n    cooldown++\n    frameNum++\n\n    if (props.loop) {\n      if (frameNum >= animation.length) { emit('loop', animation[animation.length - 1].name) }\n      frameNum %= animation.length\n    }\n    else {\n      if (frameNum >= animation.length) {\n        frameHeldOnLoopEnd = true\n        frameNum = props.resetOnEnd ? 0 : animation.length - 1\n        emit('end', animation[animation.length - 1].name)\n      }\n    }\n  }\n\n  if (animation[frameNum] !== frame) {\n    frame = animation[frameNum]\n    frameNameToEmit = frame.name\n    render()\n  }\n\n  if (dirtyFlag) {\n    dirtyFlag = false\n\n    texture.offset.x = frame.offsetX + (props.flipX ? frame.repeatX : 0)\n    texture.offset.y = frame.offsetY\n    texture.repeat.x = frame.repeatX * (props.flipX ? -1 : 1)\n    texture.repeat.y = frame.repeatY\n    texture.updateMatrix()\n\n    scaleX.value = frame.width * TEXTURE_PX_TO_WORLD_UNITS\n    scaleY.value = frame.height * TEXTURE_PX_TO_WORLD_UNITS\n\n    positionX.value = (0.5 - centerX) * frame.width * TEXTURE_PX_TO_WORLD_UNITS\n    positionY.value = (0.5 - centerY) * frame.height * TEXTURE_PX_TO_WORLD_UNITS\n  }\n\n  if (frameNameToEmit) {\n    emit('frame', frameNameToEmit)\n    frameNameToEmit = null\n  }\n})\n\nfunction render() {\n  dirtyFlag = true\n}\n\nwatch(() => props.animation, (newValue, oldValue) => {\n  if (JSON.stringify(newValue) === JSON.stringify(oldValue)) {\n    return\n  }\n  animation = getAtlasFrames(atlas, props.animation, props.reversed)\n  frameNum = 0\n  cooldown = 1\n  frameHeldOnLoopEnd = false\n  render()\n}, { immediate: true })\n\nwatch(() => props.reversed, () => {\n  frameNum = (animation.length - frameNum - 1) % animation.length\n  animation = getAtlasFrames(atlas, props.animation, props.reversed)\n  if (frameHeldOnLoopEnd) {\n    frameNum = props.resetOnEnd ? 0 : animation.length - 1\n  }\n  render()\n})\n\nwatch(() => props.paused, () => {\n  frameHeldOnLoopEnd = false\n})\n\nwatch(() => props.loop, () => {\n  if (frameHeldOnLoopEnd && props.loop) { frameHeldOnLoopEnd = false }\n})\n\nwatch(() => props.resetOnEnd, () => {\n  if (frameHeldOnLoopEnd) {\n    frameNum = props.resetOnEnd ? 0 : animation.length - 1\n    render()\n  }\n})\n\nwatch(() => props.flipX, render)\n\nwatch(() => [props.center], () => {\n  [centerX, centerY] = normalizeVectorFlexibleParam(props.center as number[])\n  render()\n}, { immediate: true })\n\nwatch(() => [props.definitions], () => {\n  setAtlasDefinitions(atlas, props.definitions)\n  // NOTE: Must reset animation, as running animation might have changed.\n  animation = getAtlasFrames(atlas, props.animation, props.reversed)\n  cooldown = 1\n  frameNum = 0\n  render()\n}, { immediate: true })\n\nonUnmounted(() => {\n  texture.dispose()\n})\n</script>\n\n<template>\n  <TresGroup\n    ref=\"groupRef\"\n  >\n    <template v-if=\"props.asSprite\">\n      <TresSprite\n        :scale=\"[scaleX, scaleY, 1]\"\n        :position=\"[positionX, positionY, 0]\"\n      >\n        <TresSpriteMaterial\n          :toneMapped=\"false\"\n          :map=\"texture\"\n          :transparent=\"true\"\n          :alphaTest=\"props.alphaTest\"\n        />\n      </TresSprite>\n    </template>\n    <template v-else>\n      <TresMesh\n        :scale=\"[scaleX, scaleY, 1]\"\n        :position=\"[positionX, positionY, 0]\"\n      >\n        <TresPlaneGeometry :args=\"[1, 1]\" />\n        <TresMeshBasicMaterial\n          :toneMapped=\"false\"\n          :side=\"DoubleSide\"\n          :map=\"texture\"\n          :transparent=\"true\"\n          :alphaTest=\"props.alphaTest\"\n          :depthWrite=\"props.depthWrite\"\n          :depthTest=\"props.depthTest\"\n        />\n      </TresMesh>\n    </template>\n    <slot></slot>\n  </TresGroup>\n</template>\n"
  },
  {
    "path": "src/core/abstractions/Billboard.vue",
    "content": "<script setup lang=\"ts\">\nimport type { Camera } from 'three'\nimport { Euler, Group, Quaternion } from 'three'\nimport { shallowRef } from 'vue'\nimport { useLoop, useTresContext } from '@tresjs/core'\n\nexport interface BillboardProps {\n  /**\n   * Whether the Billboard should face the camera automatically on every frame.\n   */\n  autoUpdate?: boolean\n  /**\n   * Whether to lock the x-axis.\n   */\n  lockX?: boolean\n  /**\n   * Whether to lock the y-axis.\n   */\n  lockY?: boolean\n  /**\n   * Whether to lock the z-axis.\n   */\n  lockZ?: boolean\n}\n\nconst props = withDefaults(defineProps<BillboardProps>(), {\n  autoUpdate: true,\n  lockX: false,\n  lockY: false,\n  lockZ: false,\n})\n\nconst outerRef = shallowRef(new Group())\nconst innerRef = shallowRef(new Group())\nconst q = new Quaternion()\nconst r = new Euler()\n\nfunction update(camera?: Camera) {\n  if (!outerRef.value) { return }\n\n  if (!camera) {\n    const { camera: ctxCamera } = useTresContext()\n    camera = ctxCamera.activeCamera.value\n    if (!camera) { return }\n  }\n\n  // NOTE: Save current rotation in case we're locking an axis\n  innerRef.value.rotation.copy(r)\n\n  // NOTE: Face the camera\n  outerRef.value.updateMatrix()\n  outerRef.value.updateWorldMatrix(false, false)\n  outerRef.value.getWorldQuaternion(q)\n  camera.getWorldQuaternion(innerRef.value.quaternion).premultiply(q.invert())\n\n  // NOTE: Overwrite locked axes\n  if (props.lockX) { innerRef.value.rotation.x = r.x }\n  if (props.lockY) { innerRef.value.rotation.y = r.y }\n  if (props.lockZ) { innerRef.value.rotation.z = r.z }\n}\n\nuseLoop().onBeforeRender(({ camera }) => {\n  if (props.autoUpdate) { update(camera.value) }\n})\n\ndefineExpose({ instance: outerRef, update })\n</script>\n\n<template>\n  <TresGroup ref=\"outerRef\">\n    <TresGroup ref=\"innerRef\">\n      <slot></slot>\n    </TresGroup>\n  </TresGroup>\n</template>\n"
  },
  {
    "path": "src/core/abstractions/CubeCamera/component.vue",
    "content": "<script setup lang=\"ts\">\nimport { useLoop } from '@tresjs/core'\nimport type { Group } from 'three'\nimport type { CubeCameraOptions } from './useCubeCamera'\nimport { useCubeCamera } from './useCubeCamera'\nimport type { MaybeRefOrGetter } from 'vue'\nimport { shallowRef, toValue } from 'vue'\n\ntype Props = {\n  /** Number of frames to render, Infinity */\n  frames?: MaybeRefOrGetter<number>\n} & CubeCameraOptions\n\nconst props = withDefaults(defineProps<Props>(), {\n  frames: Infinity,\n})\n\nconst groupRef = shallowRef<Group>()\n\nconst { fbo, camera, update } = useCubeCamera(props)\n\nlet count = 0\n\nuseLoop().onBeforeRender(() => {\n  if (groupRef.value && (props.frames === Infinity || (count < toValue(props.frames)))) {\n    groupRef.value.visible = false\n    update()\n    groupRef.value.visible = true\n\n    if (groupRef.value) {\n      groupRef.value.traverse((obj) => {\n        if ('material' in obj && typeof obj.material === 'object' && obj.material && 'envMap' in obj.material) {\n          obj.material.envMap = fbo.value.texture\n        }\n      })\n    }\n    count++\n  }\n})\n\ndefineExpose({ instance: groupRef, fbo, camera, update })\n</script>\n\n<template>\n  <TresGroup ref=\"groupRef\">\n    <primitive :object=\"camera\" />\n    <slot></slot>\n  </TresGroup>\n</template>\n"
  },
  {
    "path": "src/core/abstractions/CubeCamera/useCubeCamera.ts",
    "content": "import { useTres } from '@tresjs/core'\nimport type { TresRenderer } from '@tresjs/core'\nimport type { MaybeRefOrGetter } from 'vue'\nimport { computed, toValue, watchEffect } from 'vue'\nimport type { Fog, FogExp2, Scene, Texture } from 'three'\nimport { HalfFloatType, CubeCamera as ThreeCubeCamera, WebGLCubeRenderTarget } from 'three'\nimport { tryOnScopeDispose } from '@vueuse/core'\n\nexport interface CubeCameraOptions {\n  /** Resolution of the FBO, 255 */\n  resolution?: MaybeRefOrGetter<number>\n  /** Camera near, 0.1 */\n  near?: MaybeRefOrGetter<number>\n  /** Camera far, 1000 */\n  far?: MaybeRefOrGetter<number>\n  /** Custom environment map that is temporarily set as the scene's background */\n  envMap?: MaybeRefOrGetter<Texture>\n  /** Custom fog that is temporarily set as the scene's fog */\n  fog?: MaybeRefOrGetter<Fog | FogExp2>\n  /** Renderer */\n  renderer?: MaybeRefOrGetter<TresRenderer>\n  /** Scene */\n  scene?: MaybeRefOrGetter<Scene>\n}\n\nexport function useCubeCamera(props: CubeCameraOptions) {\n  let { resolution, renderer, scene, envMap, fog, near, far } = props\n  renderer = renderer ?? useTres().renderer\n  scene = scene ?? useTres().scene\n\n  const updateProps = () => {\n    resolution = toValue(props.resolution) ?? 255\n    near = toValue(props.near) ?? 0.1\n    far = toValue(props.far) ?? 1000\n    envMap = toValue(props.envMap) ?? undefined\n    fog = toValue(props.fog) ?? undefined\n    renderer = toValue(props.renderer) ?? renderer\n    scene = toValue(props.scene) ?? scene\n  }\n\n  watchEffect(updateProps)\n\n  const fbo = computed(() => new WebGLCubeRenderTarget(toValue(resolution)))\n  fbo.value.texture.type = HalfFloatType\n\n  tryOnScopeDispose(() => {\n    fbo.value.dispose()\n  })\n\n  const camera = computed(() => new ThreeCubeCamera(toValue(near)!, toValue(far)!, toValue(fbo)))\n\n  const update = () => {\n    const s = toValue(scene)!\n    const originalFog = s.fog\n    const originalBackground = s.background\n    s.background = toValue(envMap) || originalBackground\n    s.fog = toValue(fog) || originalFog\n    camera.value.update(toValue(renderer)!, s)\n    s.fog = originalFog\n    s.background = originalBackground\n  }\n\n  watchEffect(update)\n\n  return {\n    fbo,\n    camera,\n    update,\n  }\n}\n"
  },
  {
    "path": "src/core/abstractions/Edges.vue",
    "content": "<script setup lang=\"ts\">\nimport { ref, shallowRef, toRefs, watch } from 'vue'\nimport type { LineSegments } from 'three'\nimport { BufferGeometry, EdgesGeometry } from 'three'\nimport type { TresColor } from '@tresjs/core'\n\nexport interface EdgesProps {\n  color?: TresColor\n  threshold?: number\n}\n\nconst props = withDefaults(defineProps<EdgesProps>(), {\n  color: '#ff0000',\n  threshold: 15,\n})\n\nconst { color, threshold } = toRefs(props)\n\nconst lineSegmentsRef = shallowRef<LineSegments>()\nconst saveGeometry = ref<BufferGeometry | null>(null)\nconst saveThreshold = ref<number>(1)\n\ndefineExpose({\n  instance: lineSegmentsRef,\n})\n\n// Watch for changes in lineSegments, thresholdAngle, and color.\nwatch(\n  () => [lineSegmentsRef.value, threshold.value],\n  () => {\n    if (lineSegmentsRef.value) {\n      const parent = lineSegmentsRef.value.parent\n\n      if (parent && 'geometry' in parent && parent.geometry instanceof BufferGeometry) {\n        const geometry = parent.geometry\n\n        // Update geometry and threshold if necessary.\n        if (\n          geometry !== saveGeometry.value || threshold.value !== saveThreshold.value\n        ) {\n          saveGeometry.value = geometry\n          saveThreshold.value = threshold.value\n\n          lineSegmentsRef.value.geometry = new EdgesGeometry(geometry, threshold.value)\n        }\n      }\n    }\n  },\n)\n</script>\n\n<template>\n  <TresLineSegments\n    ref=\"lineSegmentsRef\"\n    v-bind=\"$attrs\"\n  >\n    <slot>\n      <TresLineBasicMaterial :color=\"color\" />\n    </slot>\n  </TresLineSegments>\n</template>\n"
  },
  {
    "path": "src/core/abstractions/GlobalAudio.ts",
    "content": "import { useTresContext } from '@tresjs/core'\nimport { useEventListener } from '@vueuse/core'\nimport { Audio, AudioListener, AudioLoader } from 'three'\nimport { defineComponent, onUnmounted, watch } from 'vue'\n\nexport interface AudioProps {\n  /**\n   * Path to your audio file.\n   * @type {string}\n   * @memberof AudioProps\n   *\n   */\n  src: string\n  /**\n   * Id of the DOM element that trigger the play/pause state.\n   * @type {string}\n   * @memberof AudioProps\n   * @default renderer.domElement\n   *\n   */\n  playTrigger?: string\n  /**\n   * Id of the DOM element that trigger the stop state.\n   * @type {string}\n   * @memberof AudioProps\n   * @default\n   *\n   */\n  stopTrigger?: string\n  /**\n   * If the audio must be replayed when ends.\n   * @type {boolean}\n   * @memberof AudioProps\n   * @default false\n   *\n   */\n  loop?: boolean\n  /**\n   * Volume of the audio.\n   * @type {number}\n   * @memberof AudioProps\n   * @default 0.5\n   *\n   */\n  volume?: number\n  /**\n   * PlaybackRate of the audio.\n   * @type {number}\n   * @memberof AudioProps\n   * @default 1\n   *\n   */\n  playbackRate?: number\n\n}\n\nexport const GlobalAudio = defineComponent<AudioProps>({\n  name: 'GlobalAudio',\n  props: [\n    'src',\n    'loop',\n    'volume',\n    'playbackRate',\n    'playTrigger',\n    'stopTrigger',\n  ] as unknown as undefined,\n\n  async setup(props, { expose, emit }) {\n    const { camera, renderer } = useTresContext()\n\n    const listener = new AudioListener()\n    camera.activeCamera.value?.add(listener)\n\n    const sound = new Audio(listener)\n    const audioLoader = new AudioLoader()\n\n    expose({ instance: sound })\n\n    onUnmounted(() => {\n      if (sound) {\n        sound.disconnect()\n      }\n    })\n\n    watch(() => [props.playbackRate], () => sound.setPlaybackRate(props.playbackRate ?? 1), { immediate: true })\n    watch(() => [props.volume], () => sound.setVolume(props.volume ?? 0.5), { immediate: true })\n    watch(() => [props.loop], () => sound.setLoop(props.loop ?? false), { immediate: true })\n    watch(() => [props.src], async () => {\n      const buffer = await audioLoader.loadAsync(props.src)\n      sound.setBuffer(buffer)\n    }, { immediate: true })\n\n    const selector = document.getElementById(props.playTrigger ?? '')\n    const btnPlay = selector || renderer.instance.domElement\n    useEventListener(btnPlay, 'click', () => {\n      if (sound.isPlaying) {\n        sound.pause()\n      }\n      else { sound.play() }\n      emit('isPlaying', sound.isPlaying)\n    })\n\n    const btnStop = document.getElementById(props.stopTrigger ?? '')\n    if (btnStop) {\n      useEventListener(btnStop, 'click', () => {\n        sound.stop()\n        emit('isPlaying', sound.isPlaying)\n      })\n    }\n    return null\n  },\n})\n"
  },
  {
    "path": "src/core/abstractions/GradientTexture.vue",
    "content": "<script setup lang=\"ts\">\nimport { useTres } from '@tresjs/core'\nimport * as THREE from 'three'\nimport { isReactive, shallowRef, watch } from 'vue'\n\n// NOTE: Source\n// https://github.com/pmndrs/drei/blob/master/src/core/GradientTexture.tsx\n\nexport type GradientType = 'linear' | 'radial'\n\ninterface Props {\n  /**\n   * A `number[]` of values between `0` and `1` representing the color positions in the gradient. `stops.length` should match `color.\n   */\n  stops: Array<number>\n  /**\n   * A `THREE.ColorRepresentation[]` representing the colors in the gradient.\n   */\n  colors: Array<THREE.ColorRepresentation>\n  /**\n   * Where the component should be attached within its parent.\n   */\n  attach?: string\n  /**\n   * Height of the canvas used to draw the gradient.\n   */\n  height?: number\n  /**\n   * Width of the canvas used to draw the gradient.\n   */\n  width?: number\n  /**\n   * `'linear' \\| 'radial'` Type of gradient to draw.\n   */\n  type?: GradientType\n  /**\n   * Radius of the inner circle of a radial gradient.\n   */\n  innerCircleRadius?: number\n  /**\n   * Radius of the outer circle of a radial gradient.\n   */\n  outerCircleRadius?: string | number\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n  height: 1024,\n  width: 16,\n  type: 'linear',\n  innerCircleRadius: 0,\n  outerCircleRadius: 'auto',\n  attach: 'map',\n})\n\nconst textureRef = shallowRef()\nconst canvas = document.createElement('canvas')\n\nfunction update(canvas: HTMLCanvasElement) {\n  const context = canvas.getContext('2d')!\n  canvas.width = props.width\n  canvas.height = props.height\n  let gradient\n  if (props.type === 'linear') {\n    gradient = context.createLinearGradient(0, 0, 0, props.height)\n  }\n  else {\n    const canvasCenterX = canvas.width / 2\n    const canvasCenterY = canvas.height / 2\n    const radius\n        = props.outerCircleRadius !== 'auto'\n          ? Math.abs(Number(props.outerCircleRadius))\n          : Math.sqrt(canvasCenterX ** 2 + canvasCenterY ** 2)\n    gradient = context.createRadialGradient(\n      canvasCenterX,\n      canvasCenterY,\n      Math.abs(props.innerCircleRadius),\n      canvasCenterX,\n      canvasCenterY,\n      radius,\n    )\n  }\n\n  const tempColor = new THREE.Color() // reuse instance for performance\n  let i = props.stops.length\n  while (i--) {\n    gradient.addColorStop(props.stops[i], tempColor.set(props.colors[i]).getStyle())\n  }\n  context.save()\n  context.fillStyle = gradient\n  context.fillRect(0, 0, props.width, props.height)\n  context.restore()\n\n  if (textureRef.value) {\n    textureRef.value.needsUpdate = true\n  }\n}\n\nconst renderer = useTres().renderer\n\nwatch(() => [props.colors, props.stops, props.height, props.width, props.type, props.innerCircleRadius, props.outerCircleRadius], () => { update(canvas) }, { immediate: true })\n\nif (isReactive(props.colors)) {\n  watch(props.colors, () => update(canvas))\n}\n\nif (isReactive(props.stops)) {\n  watch(props.stops, () => update(canvas))\n}\n\ndefineExpose({ instance: textureRef })\n</script>\n\n<template>\n  <TresCanvasTexture ref=\"textureRef\" :color-space=\"renderer.outputColorSpace\" :args=\"[canvas]\" :attach=\"props.attach\" />\n</template>\n"
  },
  {
    "path": "src/core/abstractions/Image/ImageMaterial.vue",
    "content": "<script setup lang=\"ts\">\nimport { shallowRef } from 'vue'\nimport { extend } from '@tresjs/core'\nimport ImageMaterial from './ImageMaterialImpl'\n\nextend({ ImageMaterial })\n\nconst materialRef = shallowRef()\n\ndefineExpose({ instance: materialRef })\n</script>\n\n<template>\n  <TresImageMaterial ref=\"materialRef\" />\n</template>\n"
  },
  {
    "path": "src/core/abstractions/Image/ImageMaterialImpl.ts",
    "content": "import { shaderMaterial } from './../../../utils/shaderMaterial'\nimport { Color, Vector2 } from 'three'\n\n/**\n * NOTE: Source:\n * https://threejs.org/docs/?q=material#api/en/materials/Material.transparent\n */\nconst imageMaterialImpl = shaderMaterial(\n  {\n    color: /* @__PURE__ */ new Color('white'),\n    scale: /* @__PURE__ */ new Vector2(1, 1),\n    imageBounds: /* @__PURE__ */ new Vector2(1, 1),\n    resolution: 1024,\n    map: null,\n    zoom: 1,\n    radius: 0,\n    grayscale: 0,\n    opacity: 1,\n  },\n  /* glsl */ `\n    varying vec2 vUv;\n    varying vec2 vPos;\n    void main() {\n      gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(position, 1.);\n      vUv = uv;\n      vPos = position.xy;\n    }\n  `,\n  /* glsl */ `\n    // mostly from https://gist.github.com/statico/df64c5d167362ecf7b34fca0b1459a44\n    varying vec2 vUv;\n    varying vec2 vPos;\n    uniform vec2 scale;\n    uniform vec2 imageBounds;\n    uniform float resolution;\n    uniform vec3 color;\n    uniform sampler2D map;\n    uniform float radius;\n    uniform float zoom;\n    uniform float grayscale;\n    uniform float opacity;\n    const vec3 luma = vec3(.299, 0.587, 0.114);\n    vec4 toGrayscale(vec4 color, float intensity) {\n      return vec4(mix(color.rgb, vec3(dot(color.rgb, luma)), intensity), color.a);\n    }\n    vec2 aspect(vec2 size) {\n      return size / min(size.x, size.y);\n    }\n    \n    const float PI = 3.14159265;\n      \n    // from https://iquilezles.org/articles/distfunctions\n    float udRoundBox( vec2 p, vec2 b, float r ) {\n      return length(max(abs(p)-b+r,0.0))-r;\n    }\n  \n    void main() {\n      vec2 s = aspect(scale);\n      vec2 i = aspect(imageBounds);\n      float rs = s.x / s.y;\n      float ri = i.x / i.y;\n      vec2 new = rs < ri ? vec2(i.x * s.y / i.y, s.y) : vec2(s.x, i.y * s.x / i.x);\n      vec2 offset = (rs < ri ? vec2((new.x - s.x) / 2.0, 0.0) : vec2(0.0, (new.y - s.y) / 2.0)) / new;\n      vec2 uv = vUv * s / new + offset;\n      vec2 zUv = (uv - vec2(0.5, 0.5)) / zoom + vec2(0.5, 0.5);\n  \n      vec2 res = vec2(scale * resolution);\n      vec2 halfRes = 0.5 * res;\n      float b = udRoundBox(vUv.xy * res - halfRes, halfRes, resolution * radius);    \n        vec3 a = mix(vec3(1.0,0.0,0.0), vec3(0.0,0.0,0.0), smoothstep(0.0, 1.0, b));\n      gl_FragColor = toGrayscale(texture2D(map, zUv) * vec4(color, opacity * a), grayscale);\n      \n      #include <tonemapping_fragment>\n      #include <colorspace_fragment>\n    }\n  `,\n)\n\nexport default imageMaterialImpl\n"
  },
  {
    "path": "src/core/abstractions/Image/component.vue",
    "content": "<script setup lang=\"ts\">\nimport type { Side, Texture } from 'three'\nimport { Color, FrontSide } from 'three'\nimport type { TresColor } from '@tresjs/core'\nimport { useTres } from '@tresjs/core'\nimport { computed, shallowRef, watchEffect } from 'vue'\nimport ImageMaterial from './ImageMaterial.vue'\nimport { useTexture } from '../../loaders/useTexture'\n\nexport type ImageProps = {\n  /**\n   * Number of divisions in the the default geometry.\n   */\n  segments?: number\n  /**\n   * Scale of the geometry.\n   */\n  scale?: number | [number, number]\n  /**\n   * Color multiplied into the image texture. Default is white.\n   */\n  color?: TresColor\n  /**\n   * Shrinks or enlarges the image texture.\n   */\n  zoom?: number\n  /**\n   * Border radius applied to image texture. Intended for rectangular geometries.\n   */\n  radius?: number\n  /**\n   * Power of grayscale effect. 0 is no grayscale. 1 is full grayscale.\n   */\n  grayscale?: number\n  /**\n   * Whether this material is tone mapped according to the renderer's toneMapping setting. [See THREE.material.tonemapped](https://threejs.org/docs/?q=material#api/en/materials/Material.toneMapped)\n   */\n  toneMapped?: boolean\n  /**\n   * Whether the image material should be transparent. [See THREE.material.transparent](https://threejs.org/docs/?q=material#api/en/materials/Material.transparent)\n   */\n  transparent?: boolean\n  /**\n   * Opacity of the image material. [See THREE.material.transparent](https://threejs.org/docs/?q=material#api/en/materials/Material.transparent)\n   */\n  opacity?: number\n  /**\n   * THREE.Side of the image material. [See THREE.material.side](https://threejs.org/docs/?q=material#api/en/materials/Material.side)\n   */\n  side?: Side\n} & ({\n  /**\n   * Image texture to display on the geometry.\n   */\n  texture: Texture\n  url?: never\n} | {\n  texture?: never\n  /**\n   * Image URL to load and display on the geometry.\n   */\n  url: string\n})\n\nconst props = withDefaults(defineProps<ImageProps>(), {\n  segments: 1,\n  scale: 1,\n  color: () => new Color('white'),\n  zoom: 1,\n  radius: 0,\n  grayscale: 0,\n  toneMapped: true,\n  transparent: false,\n  opacity: 1,\n  side: FrontSide,\n})\n\nconst imageRef = shallowRef()\nconst texture = shallowRef<Texture | null>(props.texture ?? null)\nconst size = useTres().sizes\nconst planeBounds = computed(() => Array.isArray(props.scale) ? [props.scale[0], props.scale[1]] : [props.scale, props.scale])\nconst imageBounds = computed(() => [texture.value?.image?.width ?? 0, texture.value?.image?.height ?? 0])\nconst resolution = computed(() => Math.max(size.width.value, size.height.value))\n\nwatchEffect(() => {\n  if (props.texture) {\n    texture.value = props.texture\n  }\n  else {\n    const { state: t } = useTexture(props.url!)\n    texture.value = t.value\n  }\n})\n\nconst scale = computed(\n  () => Array.isArray(props.scale)\n    ? ([...props.scale, 1] as [number, number, number])\n    : props.scale,\n)\n\ndefineExpose({ instance: imageRef })\n</script>\n\n<template>\n  <TresMesh ref=\"imageRef\" :scale=\"scale\">\n    <slot>\n      <TresPlaneGeometry :args=\"[1, 1, props.segments, props.segments]\" />\n    </slot>\n    <ImageMaterial\n      :color=\"props.color\"\n      :map=\"texture\"\n      :zoom=\"props.zoom\"\n      :grayscale=\"props.grayscale\"\n      :opacity=\"props.opacity\"\n      :scale=\"planeBounds\"\n      :imageBounds=\"imageBounds\"\n      :resolution=\"resolution\"\n      :radius=\"radius\"\n      :toneMapped=\"toneMapped\"\n      :transparent=\"transparent\"\n      :side=\"side\"\n    />\n  </TresMesh>\n</template>\n"
  },
  {
    "path": "src/core/abstractions/Lensflare/LensflareImpl.ts",
    "content": "/* eslint-disable style/no-tabs */\nimport type {\n  Texture,\n  TextureDataType,\n} from 'three'\nimport {\n  AdditiveBlending,\n  Box2,\n  BufferGeometry,\n  Color,\n  FramebufferTexture,\n  InterleavedBuffer,\n  InterleavedBufferAttribute,\n  Mesh,\n  MeshBasicMaterial,\n  RawShaderMaterial,\n  UnsignedByteType,\n  Vector2,\n  Vector3,\n  Vector4,\n} from 'three'\n\nclass Lensflare extends Mesh {\n  static Geometry: BufferGeometry\n  isLensflare = true\n  type = 'Lensflare'\n\n  addElement(_: LensflareElement) {}\n  dispose() {}\n\n  constructor() {\n    super(Lensflare.Geometry, new MeshBasicMaterial({ opacity: 0, transparent: true }))\n\n    this.frustumCulled = false\n    this.renderOrder = Infinity\n\n    //\n\n    const positionScreen = new Vector3()\n    const positionView = new Vector3()\n\n    // textures\n\n    const tempMap = new FramebufferTexture(16, 16)\n    const occlusionMap = new FramebufferTexture(16, 16)\n\n    let currentType: TextureDataType = UnsignedByteType\n\n    // material\n\n    const geometry = Lensflare.Geometry\n\n    const material1a = new RawShaderMaterial({\n      uniforms: {\n        scale: { value: null },\n        screenPosition: { value: null },\n      },\n      vertexShader: /* glsl */`\n\n\t\t\t\tprecision highp float;\n\n\t\t\t\tuniform vec3 screenPosition;\n\t\t\t\tuniform vec2 scale;\n\n\t\t\t\tattribute vec3 position;\n\n\t\t\t\tvoid main() {\n\n\t\t\t\t\tgl_Position = vec4( position.xy * scale + screenPosition.xy, screenPosition.z, 1.0 );\n\n\t\t\t\t}`,\n\n      fragmentShader: /* glsl */`\n\n\t\t\t\tprecision highp float;\n\n\t\t\t\tvoid main() {\n\n\t\t\t\t\tgl_FragColor = vec4( 1.0, 0.0, 1.0, 1.0 );\n\n\t\t\t\t}`,\n      depthTest: true,\n      depthWrite: false,\n      transparent: false,\n    })\n\n    const material1b = new RawShaderMaterial({\n      uniforms: {\n        map: { value: tempMap },\n        scale: { value: null },\n        screenPosition: { value: null },\n      },\n      vertexShader: /* glsl */`\n\n\t\t\t\tprecision highp float;\n\n\t\t\t\tuniform vec3 screenPosition;\n\t\t\t\tuniform vec2 scale;\n\n\t\t\t\tattribute vec3 position;\n\t\t\t\tattribute vec2 uv;\n\n\t\t\t\tvarying vec2 vUV;\n\n\t\t\t\tvoid main() {\n\n\t\t\t\t\tvUV = uv;\n\n\t\t\t\t\tgl_Position = vec4( position.xy * scale + screenPosition.xy, screenPosition.z, 1.0 );\n\n\t\t\t\t}`,\n\n      fragmentShader: /* glsl */`\n\n\t\t\t\tprecision highp float;\n\n\t\t\t\tuniform sampler2D map;\n\n\t\t\t\tvarying vec2 vUV;\n\n\t\t\t\tvoid main() {\n\n\t\t\t\t\tgl_FragColor = texture2D( map, vUV );\n\n\t\t\t\t}`,\n      depthTest: false,\n      depthWrite: false,\n      transparent: false,\n    })\n\n    // the following object is used for occlusionMap generation\n\n    const mesh1 = new Mesh(geometry, material1a)\n\n    //\n\n    const elements: LensflareElement[] = []\n\n    const shader = LensflareElement.Shader\n\n    const material2 = new RawShaderMaterial({\n      name: shader.name,\n      uniforms: {\n        map: { value: null },\n        occlusionMap: { value: occlusionMap },\n        color: { value: new Color(0xFFFFFF) },\n        scale: { value: new Vector2() },\n        screenPosition: { value: new Vector3() },\n      },\n      vertexShader: shader.vertexShader,\n      fragmentShader: shader.fragmentShader,\n      blending: AdditiveBlending,\n      transparent: true,\n      depthWrite: false,\n    })\n\n    const mesh2 = new Mesh(geometry, material2)\n\n    this.addElement = function (element) {\n      elements.push(element)\n    }\n\n    //\n\n    const scale = new Vector2()\n    const screenPositionPixels = new Vector2()\n    const validArea = new Box2()\n    const viewport = new Vector4()\n\n    this.onBeforeRender = function (renderer, _scene, camera) {\n      renderer.getCurrentViewport(viewport)\n\n      const renderTarget = renderer.getRenderTarget()\n      const type: TextureDataType = ((renderTarget !== null) ? renderTarget.texture.type : UnsignedByteType)\n\n      if (currentType !== type) {\n        tempMap.dispose()\n        occlusionMap.dispose()\n\n        tempMap.type = occlusionMap.type = type\n\n        currentType = type\n      }\n\n      const invAspect = viewport.w / viewport.z\n      const halfViewportWidth = viewport.z / 2.0\n      const halfViewportHeight = viewport.w / 2.0\n\n      let size = 16 / viewport.w\n      scale.set(size * invAspect, size)\n\n      validArea.min.set(viewport.x, viewport.y)\n      validArea.max.set(viewport.x + (viewport.z - 16), viewport.y + (viewport.w - 16))\n\n      // calculate position in screen space\n\n      positionView.setFromMatrixPosition(this.matrixWorld)\n      positionView.applyMatrix4(camera.matrixWorldInverse)\n\n      if (positionView.z > 0) { return } // lensflare is behind the camera\n\n      positionScreen.copy(positionView).applyMatrix4(camera.projectionMatrix)\n\n      // horizontal and vertical coordinate of the lower left corner of the pixels to copy\n\n      screenPositionPixels.x = viewport.x + (positionScreen.x * halfViewportWidth) + halfViewportWidth - 8\n      screenPositionPixels.y = viewport.y + (positionScreen.y * halfViewportHeight) + halfViewportHeight - 8\n\n      // screen cull\n\n      if (validArea.containsPoint(screenPositionPixels)) {\n        // save current RGB to temp texture\n\n        renderer.copyFramebufferToTexture(tempMap, screenPositionPixels)\n\n        // render pink quad\n\n        let uniforms = material1a.uniforms\n        uniforms.scale.value = scale\n        uniforms.screenPosition.value = positionScreen\n\n        // @ts-expect-error - allow null, `scene` is not needed\n        renderer.renderBufferDirect(camera, null, geometry, material1a, mesh1, null)\n\n        // copy result to occlusionMap\n\n        renderer.copyFramebufferToTexture(occlusionMap, screenPositionPixels)\n\n        // restore graphics\n\n        uniforms = material1b.uniforms\n        uniforms.scale.value = scale\n        uniforms.screenPosition.value = positionScreen\n\n        // @ts-expect-error - allow null, `scene` is not needed\n        renderer.renderBufferDirect(camera, null, geometry, material1b, mesh1, null)\n\n        // render elements\n\n        const vecX = -positionScreen.x * 2\n        const vecY = -positionScreen.y * 2\n\n        for (let i = 0, l = elements.length; i < l; i++) {\n          const element = elements[i]\n\n          const uniforms = material2.uniforms\n\n          uniforms.color.value.copy(element.color)\n          uniforms.map.value = element.texture\n          uniforms.screenPosition.value.x = positionScreen.x + vecX * element.distance\n          uniforms.screenPosition.value.y = positionScreen.y + vecY * element.distance\n\n          size = element.size / viewport.w\n          const invAspect = viewport.w / viewport.z\n\n          uniforms.scale.value.set(size * invAspect, size)\n\n          material2.uniformsNeedUpdate = true\n\n          // @ts-expect-error - allow null, `scene` is not needed\n          renderer.renderBufferDirect(camera, null, geometry, material2, mesh2, null)\n        }\n      }\n    }\n\n    this.dispose = function () {\n      material1a.dispose()\n      material1b.dispose()\n      material2.dispose()\n\n      tempMap.dispose()\n      occlusionMap.dispose()\n\n      for (let i = 0, l = elements.length; i < l; i++) {\n        elements[i].texture.dispose()\n      }\n    }\n  }\n}\n\n//\n\nclass LensflareElement {\n  texture: Texture\n  size: number\n  distance: number\n  color: Color\n  static Shader: { name: string, vertexShader: string, fragmentShader: string, uniforms: Record<string, any> }\n\n  constructor(texture: Texture, size = 1, distance = 0, color = new Color(0xFFFFFF)) {\n    this.texture = texture\n    this.size = size\n    this.distance = distance\n    this.color = color\n  }\n}\n\nLensflareElement.Shader = {\n\n  name: 'LensflareElementShader',\n\n  uniforms: {\n\n    map: { value: null },\n    occlusionMap: { value: null },\n    color: { value: null },\n    scale: { value: null },\n    screenPosition: { value: null },\n\n  },\n\n  vertexShader: /* glsl */`\n\n\t\tprecision highp float;\n\n\t\tuniform vec3 screenPosition;\n\t\tuniform vec2 scale;\n\n\t\tuniform sampler2D occlusionMap;\n\n\t\tattribute vec3 position;\n\t\tattribute vec2 uv;\n\n\t\tvarying vec2 vUV;\n\t\tvarying float vVisibility;\n\n\t\tvoid main() {\n\n\t\t\tvUV = uv;\n\n\t\t\tvec2 pos = position.xy;\n\n\t\t\tvec4 visibility = texture2D( occlusionMap, vec2( 0.1, 0.1 ) );\n\t\t\tvisibility += texture2D( occlusionMap, vec2( 0.5, 0.1 ) );\n\t\t\tvisibility += texture2D( occlusionMap, vec2( 0.9, 0.1 ) );\n\t\t\tvisibility += texture2D( occlusionMap, vec2( 0.9, 0.5 ) );\n\t\t\tvisibility += texture2D( occlusionMap, vec2( 0.9, 0.9 ) );\n\t\t\tvisibility += texture2D( occlusionMap, vec2( 0.5, 0.9 ) );\n\t\t\tvisibility += texture2D( occlusionMap, vec2( 0.1, 0.9 ) );\n\t\t\tvisibility += texture2D( occlusionMap, vec2( 0.1, 0.5 ) );\n\t\t\tvisibility += texture2D( occlusionMap, vec2( 0.5, 0.5 ) );\n\n\t\t\tvVisibility =        visibility.r / 9.0;\n\t\t\tvVisibility *= 1.0 - visibility.g / 9.0;\n\t\t\tvVisibility *=       visibility.b / 9.0;\n\n\t\t\tgl_Position = vec4( ( pos * scale + screenPosition.xy ).xy, screenPosition.z, 1.0 );\n\n\t\t}`,\n\n  fragmentShader: /* glsl */`\n\n\t\tprecision highp float;\n\n\t\tuniform sampler2D map;\n\t\tuniform vec3 color;\n\n\t\tvarying vec2 vUV;\n\t\tvarying float vVisibility;\n\n\t\tvoid main() {\n\n\t\t\tvec4 texture = texture2D( map, vUV );\n\t\t\ttexture.a *= vVisibility;\n\t\t\tgl_FragColor = texture;\n\t\t\tgl_FragColor.rgb *= color;\n\n\t\t}`,\n\n}\n\nLensflare.Geometry = (function () {\n  const geometry = new BufferGeometry()\n\n  const float32Array = new Float32Array([\n    -1,\n    -1,\n    0,\n    0,\n    0,\n    1,\n    -1,\n    0,\n    1,\n    0,\n    1,\n    1,\n    0,\n    1,\n    1,\n    -1,\n    1,\n    0,\n    0,\n    1,\n  ])\n\n  const interleavedBuffer = new InterleavedBuffer(float32Array, 5)\n\n  geometry.setIndex([0, 1, 2,\t0, 2, 3])\n  geometry.setAttribute('position', new InterleavedBufferAttribute(interleavedBuffer, 3, 0, false))\n  geometry.setAttribute('uv', new InterleavedBufferAttribute(interleavedBuffer, 2, 3, false))\n\n  return geometry\n})()\n\nexport { Lensflare, LensflareElement }\n"
  },
  {
    "path": "src/core/abstractions/Lensflare/RandUtils.ts",
    "content": "import { MathUtils } from 'three'\n\nconst clamp = MathUtils.clamp\n\n/**\n * Seedable pseudorandom number tools\n */\nexport default class RandUtils {\n  private _getNext: () => number\n  private _getGenerator: (seed: number) => () => number\n\n  /**\n   * Create a new seeded pseudorandom number generator.\n   * @param [seed] - the seed for the generator\n   * @param [getSeededRandomGenerator] - a function that returns a pseudorandom number generator\n   * @constructor\n   */\n  constructor(seed = 0, getSeededRandomGenerator?: (seed: number) => () => number) {\n    this._getGenerator = getSeededRandomGenerator ?? this.getMulberry32\n    this._getNext = this._getGenerator(seed)\n  }\n\n  /**\n   * Reseed the pseudorandom number generator\n   */\n  seed(s: number) {\n    this._getNext = this._getGenerator(s)\n  }\n\n  /**\n   * Return the next pseudorandom number in the interval [0, 1]\n   */\n  rand(): number {\n    return this._getNext()\n  }\n\n  /**\n   * Random float from <low, high> interval\n   * @param low - Low value of the interval\n   * @param high - High value of the interval\n   */\n  float(low: number, high: number): number {\n    return low + this._getNext() * (high - low)\n  }\n\n  /**\n   * Random float from <-range/2, range/2> interval\n   * @param range - Interval range\n   */\n  floatSpread(range: number): number {\n    return this.float(-0.5 * range, 0.5 * range)\n  }\n\n  /**\n   * Random integer from <low, high> interval\n   * @param low Low value of the interval\n   * @param high High value of the interval\n   */\n  int(low: number, high: number): number {\n    return low + Math.floor(this._getNext() * (high - low + 1))\n  }\n\n  /**\n   * Choose an element from an array.\n   * @param array The array to choose from\n   * @returns An element from the array or null if the array is empty\n   */\n  choice<T>(array: T[]): T | null {\n    if (!array.length) {\n      return null\n    }\n    return array[Math.floor(this._getNext() * array.length)]\n  }\n\n  /**\n   * Choose an element from an array or return defaultValue if array is empty.\n   * @param array The array to choose from\n   * @param defaultValue The value to return if the array is empty\n   * @returns An element from the array or defaultValue if the array is empty\n   */\n  defaultChoice<T>(array: T[], defaultValue: T): T {\n    if (!array.length) {\n      return defaultValue\n    }\n    return array[Math.floor(this._getNext() * array.length)]\n  }\n\n  /**\n   * Return n elements from an array.\n   * @param array The array to sample\n   * @param sampleSizeMin The minimum sample size\n   * @param sampleSizeMax The maximum sample size\n   */\n  sample<T>(array: T[], sampleSizeMin: number, sampleSizeMax?: number): T[] {\n    const len = array.length\n    sampleSizeMin = clamp(sampleSizeMin, 0, len - 1)\n    sampleSizeMax = clamp(sampleSizeMax ?? len - 1, 0, len - 1)\n    const sampleSize = this.int(sampleSizeMin, sampleSizeMax)\n    const indicies = this.shuffle(array.map((_, i) => i))\n    const n = Math.min(array.length, sampleSize)\n    return indicies\n      .slice(0, n)\n      .sort()\n      .map(i => array[i])\n  }\n\n  /**\n   * Shuffle an array. Not in-place.\n   * @param array The array to shuffle\n   */\n  shuffle<T>(array: T[]): T[] {\n    return array\n      .map(value => ({ value, sort: this._getNext() }))\n      .sort((a, b) => a.sort - b.sort)\n      .map(({ value }) => value)\n  }\n\n  /**\n   * The default pseudorandom generator.\n   */\n  private getMulberry32(seed = 0): () => number {\n    if (seed > 0 && seed < 1) {\n      seed = Math.floor(seed * 2 ** 16)\n    }\n    return () => {\n      // NOTE: Mulberry32 generator\n      seed += 0x6D2B79F5\n      let t = seed\n      t = Math.imul(t ^ (t >>> 15), t | 1)\n      t ^= t + Math.imul(t ^ (t >>> 7), t | 61)\n      return ((t ^ (t >>> 14)) >>> 0) / 4294967296\n    }\n  }\n}\n"
  },
  {
    "path": "src/core/abstractions/Lensflare/component.vue",
    "content": "<script setup lang=\"ts\">\nimport { normalizeColor } from '@tresjs/core'\nimport { TextureLoader } from 'three'\n// TODO:\n// three-stdlib's Lensflare is not currently working.\n// PR here: https://github.com/pmndrs/three-stdlib/issues/396\n// Once three-stdlib's Lensflare is fixed, use it below\n// and delete ./LensflareImpl from the repo.\nimport { Lensflare } from './LensflareImpl'\nimport { onMounted, onUnmounted, shallowRef, watch } from 'vue'\nimport type { TresColor } from '@tresjs/core'\nimport type { Texture } from 'three'\nimport type { LensflareElement } from 'three-stdlib'\nimport { partialLensflarePropsArrayToLensflarePropsArray as fillInProps, filterLensflareElementProps } from '.'\nimport type { LensflareElementProps, SeedProps } from '.'\n\nexport interface LensflareProps {\n  /**\n   * scale of the lensflare\n   */\n  scale?: number\n  /**\n   * array of lensflare element properties\n   */\n  elements?: Partial<LensflareElementProps>[]\n  /**\n   * random seed for generating random seeded elements\n   */\n  seed?: number\n  /**\n   * specifications for generating random seeded elements\n   */\n  seedProps?: SeedProps[]\n  /**\n   * default color of lensflare elements\n   */\n  color?: TresColor\n  /**\n   *  default distance of lensflare elements from flare center\n   */\n  distance?: number\n  /**\n   *  default size of lensflare elements\n   */\n  size?: number\n  /**\n   * default texture of lensflare elements\n   */\n  texture?: Texture | string\n}\n\nconst props = withDefaults(defineProps<LensflareProps>(), {\n  scale: 1.0,\n  elements: undefined,\n  seed: undefined,\n  seedProps: undefined,\n  color: undefined,\n  distance: undefined,\n  size: undefined,\n  texture: undefined,\n})\n\nconst lensflareRef = shallowRef<Lensflare>()\nconst lensflareElementPropsArrayRef = shallowRef<LensflareElementProps[]>([])\nconst userDefaultLensflareElementPropsRef\n  = shallowRef<Partial<LensflareElementProps>>(filterLensflareElementProps(props))\n\ndefineExpose({\n  instance: lensflareRef,\n})\n\nconst textureLoader = new TextureLoader()\n\nconst threeLensflare = new Lensflare()\n// NOTE: THREE.Lensflare doesn't expose `elements` – the \"parts\" of a lensflare.\n// We'll maintain references that we can update.\nconst threeElements: LensflareElement[] = []\n\nconst dispose = () => {\n  while (threeElements.length) { threeElements.pop() }\n  lensflareRef.value?.children.forEach((c: any) => {\n    if ('dispose' in c) {\n      c.dispose()\n    }\n  })\n  lensflareRef.value?.remove(...lensflareRef.value.children)\n  lensflareRef.value?.dispose()\n}\n\nconst lensflareElementPropsToLensflareElement = (p: LensflareElementProps) => {\n  if (typeof p.texture === 'string') {\n    const path = p.texture\n    p.texture = textureLoader.load(path)\n    p.texture.name = path\n  }\n  p.color = normalizeColor(p.color)\n  return p as LensflareElement\n}\n\nconst scaleThreeElements = () => {\n  // NOTE: We can't remove already added elements from the THREE lensflare.\n  // So if we've previously added more elements than are currently needed,\n  // make those elements too small to display.\n  for (let i = lensflareElementPropsArrayRef.value.length - 1; i < threeElements.length; i++) {\n    threeElements[i].size = 0\n  }\n\n  lensflareElementPropsArrayRef.value.forEach((elementProps, i) => {\n    threeElements[i].size = elementProps.size * props.scale\n  })\n}\n\nconst updateThreeElements = () => {\n  while (lensflareElementPropsArrayRef.value.length > threeElements.length) {\n    const element = lensflareElementPropsToLensflareElement(lensflareElementPropsArrayRef.value[threeElements.length])\n    const copy = { ...element }\n    threeElements.push(copy)\n    threeLensflare.addElement(copy)\n  }\n\n  lensflareElementPropsArrayRef.value.forEach((elementProps, i) => {\n    const threeElement = threeElements[i]\n    const { texture, size, distance, color } = elementProps\n    if (typeof texture === 'string') {\n      if (threeElement.texture.name !== texture) {\n        threeElement.texture.dispose()\n        const name = texture\n        threeElement.texture = textureLoader.load(name)\n        threeElement.texture.name = name\n      }\n    }\n    else {\n      if (threeElement.texture !== texture) {\n        threeElement.texture.dispose()\n        threeElement.texture = texture\n      }\n    }\n\n    threeElement.size = size\n    threeElement.distance = distance\n    threeElement.color = normalizeColor(color)\n  })\n\n  scaleThreeElements()\n}\n\nonUnmounted(() => {\n  dispose()\n})\n\nonMounted(() => {\n  lensflareRef.value?.add(threeLensflare)\n  lensflareElementPropsArrayRef.value\n    = fillInProps(props.elements, userDefaultLensflareElementPropsRef.value, props.seed, props.seedProps)\n})\n\nwatch(() => [props.color, props.distance, props.size, props.texture], () => {\n  userDefaultLensflareElementPropsRef.value = {\n    color: props.color,\n    distance: props.distance,\n    size: props.size,\n    texture: props.texture as Texture | string,\n  }\n})\n\nwatch(() => [userDefaultLensflareElementPropsRef.value, props.elements, props.seed, props.seedProps], () => {\n  lensflareElementPropsArrayRef.value\n    = fillInProps(props.elements, userDefaultLensflareElementPropsRef.value, props.seed, props.seedProps)\n})\n\nwatch(() => props.scale, () => {\n  scaleThreeElements()\n})\n\nwatch(() => lensflareElementPropsArrayRef.value, () => {\n  updateThreeElements()\n})\n</script>\n\n<template>\n  <TresGroup ref=\"lensflareRef\" />\n</template>\n"
  },
  {
    "path": "src/core/abstractions/Lensflare/constants.ts",
    "content": "import type { LensflareElementProps, SeedProps } from '.'\n\nexport const TEXTURE_PATH\n  = 'https://raw.githubusercontent.com/Tresjs/assets/93976c7d63ac83d4a254a41a10b2362bc17e90c9/textures/lensflare/'\n\nexport const circle = `${TEXTURE_PATH}circle.png`\nexport const circleBlur = `${TEXTURE_PATH}circleBlur.png`\nexport const circleRainbow = `${TEXTURE_PATH}circleRainbow.png`\nexport const line = `${TEXTURE_PATH}line.png`\nexport const poly6 = `${TEXTURE_PATH}poly6.png`\nexport const polyStroke6 = `${TEXTURE_PATH}polyStroke6.png`\nexport const rays = `${TEXTURE_PATH}rays.png`\nexport const ring = `${TEXTURE_PATH}ring.png`\nexport const starThin6 = `${TEXTURE_PATH}starThin6.png`\n\n// NOTE:\n// Flare elements are divided into back, oversize, body, front.\n// They are arranged as such, relative to the light source and camera:\n//\n// | distance < 0 | distance == 0  | distance > 0 | camera |\n// | ------------ | -------------- | ------------ | ------ |\n// |              |     light      |              |        |\n// | back         | body, oversize | front        |        |\n\nexport const oversize: SeedProps = {\n  texture: [line, ring],\n  color: ['white'],\n  distance: [0, 0],\n  size: [750, 1024],\n  length: [0, 2],\n}\n\nexport const bodyRequired0: SeedProps = {\n  texture: [circleBlur],\n  color: ['white'],\n  distance: [0, 0],\n  size: [180, 512],\n  length: [1, 1],\n}\n\nexport const bodyRequired1: SeedProps = {\n  texture: [rays],\n  color: ['white'],\n  distance: [0, 0],\n  size: [180, 512],\n  length: [1, 1],\n}\n\nexport const bodyOptional: SeedProps = {\n  texture: [circle, circleRainbow, ring, starThin6],\n  color: ['white'],\n  distance: [0, 0],\n  size: [180, 512],\n  length: [2, 3],\n}\n\nexport const [darkPurple, darkBlue] = [0x38235F, 0x02055A]\n\nexport const front: SeedProps = {\n  texture: [circleBlur, circle, ring, poly6, polyStroke6],\n  color: ['dimgray', 'gray', 'darkgray', darkPurple, darkBlue],\n  distance: [0.5, 2.5],\n  size: [20, 180],\n  length: [5, 21],\n}\n\nexport const back: SeedProps = {\n  texture: [circleBlur, circle, ring, poly6, polyStroke6],\n  color: ['dimgray', 'gray', 'darkgray', darkPurple, darkBlue],\n  distance: [-0.6, -0.1],\n  size: [180, 360],\n  length: [0, 5],\n}\n\nexport const defaultSeedProps: SeedProps[] = [oversize, bodyRequired0, bodyRequired1, bodyOptional, front, back]\n\nexport const defaultLensflareElementProps: LensflareElementProps = {\n  color: 'white',\n  distance: 0,\n  size: 512,\n  texture: circleBlur,\n}\n"
  },
  {
    "path": "src/core/abstractions/Lensflare/index.ts",
    "content": "import { MathUtils } from 'three'\nimport type { TresColor } from '@tresjs/core'\nimport type { Texture } from 'three'\nimport {\n  easeInCubic,\n  easeInOutCubic,\n  easeInQuart,\n  easeOutBounce,\n  linear,\n} from '../../../utils/easing'\nimport Lensflare from './component.vue'\nimport { defaultLensflareElementProps, defaultSeedProps } from './constants'\nimport RandUtils from './RandUtils'\n\nexport { Lensflare }\n\nexport interface SeedProps {\n  texture: string[]\n  color: TresColor[]\n  distance: [number, number]\n  size: [number, number]\n  length: [number, number]\n  seed?: number\n}\n\nconst easingFunctions = [\n  linear,\n  easeInCubic,\n  easeInOutCubic,\n  easeInQuart,\n  easeOutBounce,\n]\n\nconst lerp = MathUtils.lerp\n\nconst getSeededRandomProps = (\n  seed = 0,\n  seedProps = defaultSeedProps,\n): LensflareElementProps[] => {\n  const rand: RandUtils = new RandUtils(seed)\n\n  const easingFn = rand.choice(easingFunctions) as (n: number) => number\n\n  return seedProps\n    .map((preset, i) => {\n      const rand: RandUtils = new RandUtils(\n        seed * (i * 7907 + 1)\n        + (typeof preset.seed === 'number' ? preset.seed : 0),\n      )\n      const numElements = rand.int(preset.length[0], preset.length[1])\n      return Array.from({ length: numElements }).fill(0).map(() => {\n        const progress = easingFn(rand.rand())\n        return {\n          texture: rand.defaultChoice(\n            preset.texture,\n            defaultLensflareElementProps.texture,\n          ),\n          size: lerp(preset.size[0], preset.size[1], easingFn(1 - progress)),\n          distance: lerp(preset.distance[0], preset.distance[1], progress),\n          color: rand.defaultChoice(\n            preset.color,\n            defaultLensflareElementProps.color,\n          ),\n        }\n      })\n    })\n    .flat()\n}\n\n/**\n * To make creating a complex lensflare simpler, the component can generate some or all `LensflareElement` properties.\n * The precendence in creating the final elements' props is as follows:\n *\n * 1. `elements`\n * 2. `userDefaultElement` - `color`, `distance`, `size`, `texture` from component\n * 3. seeded random props - if `seed` and/or `seedProps` is not `undefined`\n * 4. system default\n *\n * @param elements - `undefined` or an array of (potentially) incomplete element props\n * @param userDefaultElement - values to \"fill in\" missing partial elements fields – or overwrite seeded props\n * @param seed - `undefined` or a number to seed random prop generation\n * @param seedProps - `undefined` or an array of SeedProps for generating random seeded properties\n * @param systemDefaultElement - default values to \"fill in\" any remaining missing props\n * @returns LensflareElementProps[] - An array of complete props\n */\n\nexport const partialLensflarePropsArrayToLensflarePropsArray = (\n  elements: Partial<LensflareElementProps>[] | undefined,\n  userDefaultElement: Partial<LensflareElementProps>,\n  seed: number | undefined = undefined,\n  seedProps: SeedProps[] | undefined = undefined,\n  systemDefaultElement = defaultLensflareElementProps,\n): LensflareElementProps[] => {\n  if (elements !== undefined && elements.length > 0 && (typeof seed === 'number' || typeof seedProps !== 'undefined')) {\n    const seeded = getSeededRandomProps(seed ?? 0, seedProps ?? defaultSeedProps)\n    const seededLength = seeded.length\n    const elementsLength = elements.length\n    if (seededLength >= elementsLength) {\n      return seeded.map((_seededProps, i) =>\n        Object.assign(_seededProps, userDefaultElement, i < elementsLength ? elements[i] : {}),\n      )\n    }\n    else {\n      return elements.map((_element, i) =>\n        Object.assign({}, systemDefaultElement, i < seededLength ? seeded[i] : {}, userDefaultElement, _element),\n      )\n    }\n  }\n\n  if (elements !== undefined && elements.length > 0) {\n    const fullDefaultProps = Object.assign({}, systemDefaultElement, userDefaultElement)\n    return elements.map(element => Object.assign({}, fullDefaultProps, element))\n  }\n\n  const _seedProps = (seedProps === undefined || seedProps.length === 0) ? defaultSeedProps : seedProps\n  const seededProps = getSeededRandomProps(seed ?? 0, _seedProps)\n  return seededProps.map(props => Object.assign({}, props, userDefaultElement))\n}\n\nexport interface LensflareElementProps {\n  texture: Texture | string\n  size: number\n  distance: number\n  color: TresColor\n}\n\nexport function filterLensflareElementProps(\n  props: Partial<LensflareElementProps>,\n): Partial<LensflareElementProps> {\n  return filter(props, (v, k) => k in defaultLensflareElementProps && v !== undefined)\n}\n\nfunction filter<T extends object>(\n  obj: T,\n  predicate: <K extends keyof T>(value: T[K], key: K) => boolean,\n) {\n  const result: { [K in keyof T]?: T[K] } = {};\n  (Object.keys(obj) as Array<keyof T>).forEach((name) => {\n    if (predicate(obj[name], name)) {\n      result[name] = obj[name]\n    }\n  })\n  return result\n}\n"
  },
  {
    "path": "src/core/abstractions/Levioso.vue",
    "content": "<script setup lang=\"ts\">\nimport { useLoop } from '@tresjs/core'\nimport { MathUtils } from 'three'\nimport { shallowRef } from 'vue'\n\nconst props = withDefaults(\n  defineProps<{\n    speed?: number\n    rotationFactor?: number\n    floatFactor?: number\n    range?: [number, number]\n  }>(),\n  {\n    speed: 1,\n    rotationFactor: 1,\n    floatFactor: 1,\n    range: () => [-0.1, 0.1],\n  },\n)\nconst groupRef = shallowRef()\n\ndefineExpose({\n  instance: groupRef,\n})\n\n{\n  const PERIOD_SCALE = 1 / 4\n  const AMPLITUDE_ROTATION_X = 1 / 8\n  const AMPLITUDE_ROTATION_Y = 1 / 8\n  const AMPLITUDE_ROTATION_Z = 1 / 20\n  const START_OFFSET = Math.random() * 10000\n\n  const { onBeforeRender } = useLoop()\n  let elapsed = START_OFFSET\n\n  onBeforeRender(({ delta /* invalidate */ }) => {\n    if (!groupRef.value) { return }\n\n    elapsed += delta * props.speed\n    const theta = elapsed * PERIOD_SCALE\n\n    const group = groupRef.value\n    group.rotation.x = Math.cos(theta) * AMPLITUDE_ROTATION_X * props.rotationFactor\n    group.rotation.y = Math.sin(theta) * AMPLITUDE_ROTATION_Y * props.rotationFactor\n    group.rotation.z = Math.sin(theta) * AMPLITUDE_ROTATION_Z * props.rotationFactor\n    group.position.y = MathUtils.mapLinear(Math.sin(theta), -1, 1, props.range[0], props.range[1]) * props.floatFactor\n\n    // TODO: comment this until invalidate is back in the loop callback on v5\n    // invalidate()\n  })\n}\n</script>\n\n<template>\n  <TresGroup\n    v-bind=\"$attrs\"\n    ref=\"groupRef\"\n  >\n    <slot></slot>\n  </TresGroup>\n</template>\n"
  },
  {
    "path": "src/core/abstractions/MarchingCubes/MarchingCube.vue",
    "content": "<script setup lang=\"ts\">\nimport { useLoop } from '@tresjs/core'\nimport { computed, inject, shallowRef } from 'vue'\nimport { Color, type ColorRepresentation, Vector3 } from 'three'\nimport type { MarchingCubesApi } from './MarchingCubes.vue'\nimport { MARCHING_CUBES_PROVIDE_KEY } from './const'\n\ninterface MarchingCubeProps {\n  strength?: number\n  subtract?: number\n  color?: ColorRepresentation\n}\n\nconst props = withDefaults(defineProps<MarchingCubeProps>(), {\n  strength: 0.5,\n  subtract: 12,\n})\n\nconst { parent } = inject(MARCHING_CUBES_PROVIDE_KEY) as MarchingCubesApi\nconst cubeRef = shallowRef()\nconst vec = new Vector3()\nconst color = computed(() => new Color(props.color))\n\nuseLoop().onBeforeRender(() => {\n  if (!parent.value || !cubeRef.value) { return }\n  cubeRef.value.getWorldPosition(vec)\n  parent.value.addBall(0.5 + vec.x * 0.5, 0.5 + vec.y * 0.5, 0.5 + vec.z * 0.5, props.strength, props.subtract, color.value)\n})\n\ndefineExpose({ instance: cubeRef })\n</script>\n\n<template>\n  <TresGroup ref=\"cubeRef\" />\n</template>\n"
  },
  {
    "path": "src/core/abstractions/MarchingCubes/MarchingCubes.vue",
    "content": "<script setup lang=\"ts\">\nimport { MeshBasicMaterial } from 'three'\nimport { MarchingCubes as MarchingCubesImpl } from 'three-stdlib'\nimport { computed, onUnmounted, provide } from 'vue'\nimport { useLoop } from '@tresjs/core'\nimport { MARCHING_CUBES_PROVIDE_KEY } from './const'\n\nexport interface MarchingCubesProps {\n  resolution?: number\n  maxPolyCount?: number\n  enableUvs?: boolean\n  enableColors?: boolean\n}\n\nconst props = withDefaults(defineProps<MarchingCubesProps>(), {\n  resolution: 28,\n  maxPolyCount: 10000,\n  enableUvs: false,\n  enableColors: false,\n})\n\nconst defaultMaterial = new MeshBasicMaterial()\nconst marchingCubes = computed(() => new MarchingCubesImpl(props.resolution, defaultMaterial, props.enableUvs, props.enableColors, props.maxPolyCount))\nconst api = { parent: marchingCubes }\n\nexport type MarchingCubesApi = typeof api\n\nprovide(MARCHING_CUBES_PROVIDE_KEY, api)\n\nmarchingCubes.value.reset()\n\nuseLoop().onBeforeRender(() => {\n  marchingCubes.value.update()\n  marchingCubes.value.reset()\n})\n\nonUnmounted(() => { defaultMaterial.dispose() })\n\ndefineExpose({ instance: marchingCubes })\n</script>\n\n<template>\n  <primitive :object=\"marchingCubes\">\n    <slot></slot>\n  </primitive>\n</template>\n"
  },
  {
    "path": "src/core/abstractions/MarchingCubes/MarchingPlane.vue",
    "content": "<script setup lang=\"ts\">\nimport { computed, inject, ref } from 'vue'\nimport { MARCHING_CUBES_PROVIDE_KEY } from './const'\nimport type { MarchingCubesApi } from './MarchingCubes.vue'\nimport { useLoop } from '@tresjs/core'\n\ninterface MarchingPlaneProps {\n  planeType?: 'x' | 'y' | 'z'\n  strength?: number\n  subtract?: number\n}\n\nconst props = withDefaults(defineProps<MarchingPlaneProps>(), {\n  planeType: 'x',\n  strength: 0.5,\n  subtract: 12,\n})\n\nconst { parent } = inject(MARCHING_CUBES_PROVIDE_KEY) as MarchingCubesApi\nconst wallRef = ref()\nconst planeType = computed(\n  () => (props.planeType === 'x' ? 'addPlaneX' : props.planeType === 'y' ? 'addPlaneY' : 'addPlaneZ'),\n)\n\nuseLoop().onBeforeRender(() => {\n  if (!parent.value || !wallRef.value) { return }\n  parent.value[planeType.value](props.strength, props.subtract)\n})\n</script>\n\n<template>\n  <TresGroup ref=\"wallRef\" />\n</template>\n"
  },
  {
    "path": "src/core/abstractions/MarchingCubes/const.ts",
    "content": "const MARCHING_CUBES_PROVIDE_KEY = Symbol('marchingCubes')\n\nexport { MARCHING_CUBES_PROVIDE_KEY }\n"
  },
  {
    "path": "src/core/abstractions/Mask/component.vue",
    "content": "<script setup lang=\"ts\">\nimport type { Mesh } from 'three'\nimport { AlwaysStencilFunc, ReplaceStencilOp } from 'three'\nimport { shallowRef, watchEffect } from 'vue'\n\ninterface MaskProps {\n  /** Id of the stencil buffer to use. Each mask must have an id. Multiple masks can refer to the same id. */\n  id: number\n  /** Whether the colors of the masks own material will leak through, default: false */\n  colorWrite?: boolean\n  /** Whether the depth of the masks own material will leak through, default: false */\n  depthWrite?: boolean\n}\n\nconst props = withDefaults(defineProps<MaskProps>(), {\n  id: 1,\n  colorWrite: true,\n  depthWrite: false,\n})\n\nconst meshRef = shallowRef<Mesh>()\n\nfunction update() {\n  const material = Array.isArray(meshRef.value?.material) ? meshRef.value.material[0] : meshRef.value?.material\n  if (!material) { return }\n\n  material.colorWrite = props.colorWrite\n  material.depthWrite = props.depthWrite\n  material.stencilWrite = true\n  material.stencilRef = props.id\n  material.stencilFunc = AlwaysStencilFunc\n  material.stencilFail = ReplaceStencilOp\n  material.stencilZFail = ReplaceStencilOp\n  material.stencilZPass = ReplaceStencilOp\n}\n\nwatchEffect(update)\n\ndefineExpose({ instance: meshRef })\n</script>\n\n<template>\n  <TresMesh ref=\"meshRef\" :render-order=\"-props.id\">\n    <slot></slot>\n  </TresMesh>\n</template>\n"
  },
  {
    "path": "src/core/abstractions/Mask/useMask.ts",
    "content": "import { EqualStencilFunc, KeepStencilOp, NotEqualStencilFunc } from 'three'\nimport type { Ref } from 'vue'\nimport { reactive, toValue, watchEffect } from 'vue'\n\nexport function useMask(id: Ref<number> | number, inverse: Ref<boolean> | boolean = false) {\n  const result = reactive({\n    stencilWrite: true,\n    stencilRef: toValue(id),\n    stencilFunc: toValue(inverse) ? NotEqualStencilFunc : EqualStencilFunc,\n    stencilFail: KeepStencilOp,\n    stencilZFail: KeepStencilOp,\n    stencilZPass: KeepStencilOp,\n  })\n\n  watchEffect(() => {\n    result.stencilRef = toValue(id)\n    result.stencilFunc = toValue(inverse) ? NotEqualStencilFunc : EqualStencilFunc\n  })\n\n  return result\n}\n"
  },
  {
    "path": "src/core/abstractions/MouseParallax.vue",
    "content": "<script setup lang=\"ts\">\nimport { useLoop, useTres } from '@tresjs/core'\nimport { useElementSize, useMouse, useWindowSize } from '@vueuse/core'\nimport { computed, ref, shallowRef, toRefs, watch } from 'vue'\nimport type { UseMouseOptions } from '@vueuse/core'\nimport type { Group } from 'three'\n\nexport interface MouseParallaxProps {\n  /**\n   * Whether to disable the mouse controls.\n   * @type {boolean}\n   * @default false\n   * @memberof MouseParallaxProps\n   *\n   */\n  disabled?: boolean\n  /**\n   * The factor to multiply the mouse movement by.\n   * @type {number | [number, number]}\n   * @default 2.5\n   * @memberof MouseParallaxProps\n   *\n   */\n  factor?: number | [number, number]\n  /**\n   * The factor to smooth the mouse movement by.\n   * @type {number | [number, number]}\n   * @default 2.5\n   * @memberof MouseParallaxProps\n   *\n   */\n  ease?: number | [number, number]\n  /**\n   * Whether to apply the parallax effect to the local canvas.\n   * @type {boolean}\n   * @default false\n   * @memberof MouseParallaxProps\n   *\n   */\n  local?: boolean\n}\n\nconst props = withDefaults(defineProps<MouseParallaxProps>(), {\n  disabled: false,\n  factor: 2.5,\n  ease: 0.1,\n  local: false,\n})\n\nconst { camera, renderer } = useTres()\n\nconst { disabled, factor, ease, local } = toRefs(props)\n\nconst mouseOptions: UseMouseOptions = {}\n\nif (local.value) {\n  mouseOptions.target = renderer.domElement\n  mouseOptions.type = 'client'\n}\n\nconst { x, y } = useMouse(mouseOptions)\nconst { width, height } = local.value\n  ? useElementSize(renderer.domElement)\n  : useWindowSize()\n\nconst cameraGroupRef = shallowRef<Group>()\nconst _factor = ref()\nconst _ease = ref()\n\nwatch(\n  [factor, ease],\n  () => {\n    _factor.value = Array.isArray(factor.value) ? factor.value : [factor.value, factor.value]\n    _ease.value = Array.isArray(ease.value) ? ease.value : [ease.value, ease.value]\n  },\n  { immediate: true },\n)\n\nconst cursorX = computed(() => (x.value / width.value - 0.5) * _factor.value[0])\nconst cursorY = computed(() => -(y.value / height.value - 0.5) * _factor.value[1])\n\nconst { onBeforeRender } = useLoop()\n\nonBeforeRender(({ delta /* invalidate */ }) => {\n  if (\n    disabled.value\n    || !cameraGroupRef.value\n    || Number.isNaN(cursorX.value)\n    || Number.isNaN(cursorY.value)\n  ) {\n    return\n  }\n  cameraGroupRef.value.position.x\n    += (cursorX.value - cameraGroupRef.value.position.x) * _ease.value[0] * delta\n  cameraGroupRef.value.position.y\n    += (cursorY.value - cameraGroupRef.value.position.y) * _ease.value[1] * delta\n\n  // TODO: comment this until invalidate is back in the loop callback on v5\n  // invalidate()\n})\n\nwatch(\n  () => cameraGroupRef.value,\n  value => value?.add(camera.value!),\n)\n</script>\n\n<template>\n  <TresGroup ref=\"cameraGroupRef\" />\n</template>\n"
  },
  {
    "path": "src/core/abstractions/Outline/OutlineMaterialImpl.ts",
    "content": "import { Color, Vector2 } from 'three'\nimport { shaderMaterial } from '../../../utils/shaderMaterial'\n\n// NOTE: Source\n// https://github.com/pmndrs/drei/blob/master/src/core/Outlines.tsx\n\nconst OutlineMaterialImpl = shaderMaterial(\n  {\n    screenspace: false,\n    color: new Color('black'),\n    opacity: 1,\n    thickness: 0.05,\n    size: new Vector2(1, 1),\n  },\n  `#include <common>\n   #include <morphtarget_pars_vertex>\n   #include <skinning_pars_vertex>\n   uniform float thickness;\n   uniform bool screenspace;\n   uniform vec2 size;\n   void main() {\n     #if defined (USE_SKINNING)\n       #include <beginnormal_vertex>\n       #include <morphnormal_vertex>\n       #include <skinbase_vertex>\n       #include <skinnormal_vertex>\n       #include <defaultnormal_vertex>\n     #endif\n     #include <begin_vertex>\n     #include <morphtarget_vertex>\n     #include <skinning_vertex>\n     #include <project_vertex>\n     vec4 tNormal = vec4(normal, 0.0);\n     vec4 tPosition = vec4(transformed, 1.0);\n     #ifdef USE_INSTANCING\n       tNormal = instanceMatrix * tNormal;\n       tPosition = instanceMatrix * tPosition;\n     #endif\n     if (screenspace) {\n       vec3 newPosition = tPosition.xyz + tNormal.xyz * thickness;\n       gl_Position = projectionMatrix * modelViewMatrix * vec4(newPosition, 1.0); \n     } else {\n       vec4 clipPosition = projectionMatrix * modelViewMatrix * tPosition;\n       vec4 clipNormal = projectionMatrix * modelViewMatrix * tNormal;\n       vec2 offset = normalize(clipNormal.xy) * thickness / size * clipPosition.w * 2.0;\n       clipPosition.xy += offset;\n       gl_Position = clipPosition;\n     }\n   }`,\n  `uniform vec3 color;\n   uniform float opacity;\n   void main(){\n     gl_FragColor = vec4(color, opacity);\n     #include <tonemapping_fragment>\n     #include <colorspace_fragment>\n   }`,\n)\n\nexport default OutlineMaterialImpl\n"
  },
  {
    "path": "src/core/abstractions/Outline/component.vue",
    "content": "<script setup lang=\"ts\">\nimport type { TresColor } from '@tresjs/core'\nimport { normalizeColor, useTres } from '@tresjs/core'\nimport type { BufferGeometry, Group, Material, ShaderMaterial } from 'three'\nimport { BackSide, InstancedMesh, Mesh, SkinnedMesh, Vector2 } from 'three'\nimport { onMounted, onUnmounted, shallowRef, watch } from 'vue'\nimport OutlineMaterialImpl from './OutlineMaterialImpl'\nimport { toCreasedNormals } from 'three-stdlib'\n\n// NOTE: Source\n// https://github.com/pmndrs/drei/blob/master/src/core/Outlines.tsx\n\ninterface OutlineProps {\n  /** Outline color, default: black */\n  color?: TresColor\n  /** Line thickness is independent of zoom, default: false */\n  screenspace?: boolean\n  /** Outline opacity, default: 1 */\n  opacity?: number\n  /** Outline transparency, default: false */\n  transparent?: boolean\n  /** Outline thickness, default 0.05 */\n  thickness?: number\n  /** Geometry crease angle (-1 === no crease), default: Math.PI, See [BufferGeometryUtils.toCreasedNormals](https://threejs.org/docs/#examples/en/utils/BufferGeometryUtils.toCreasedNormals) */\n  angle?: number\n  toneMapped?: boolean\n  polygonOffset?: boolean\n  polygonOffsetFactor?: number\n  renderOrder?: number\n}\n\ninterface OutlineMaterial extends ShaderMaterial {\n  thickness?: number\n  screenspace?: boolean\n  size?: Vector2\n  color?: TresColor\n}\n\nconst props = withDefaults(defineProps<OutlineProps>(), {\n  color: 'black',\n  opacity: 1,\n  transparent: false,\n  screenspace: false,\n  toneMapped: true,\n  polygonOffset: false,\n  polygonOffsetFactor: 0,\n  renderOrder: 0,\n  thickness: 0.05,\n  angle: Math.PI,\n})\n\nconst groupRef = shallowRef()\n\ndefineExpose({ instance: groupRef })\n\nconst material = new OutlineMaterialImpl({ ...props }) as OutlineMaterial\nconst contextSize = new Vector2(1, 1)\nlet oldAngle = 0\nlet oldGeometry: BufferGeometry | null = null\n\nfunction updateMesh(group: Group) {\n  const parent = group.parent as Mesh & SkinnedMesh & InstancedMesh\n  if (!parent || !parent.geometry) { return }\n\n  if (oldAngle !== props.angle || oldGeometry !== parent.geometry) {\n    oldAngle = props.angle\n    oldGeometry = parent.geometry\n\n    // NOTE: Remove old mesh\n    let mesh = group.children?.[0] as any\n    if (mesh) {\n      if (props.angle) { mesh.geometry.dispose() }\n      group.remove(mesh)\n    }\n\n    if (parent.skeleton) {\n      mesh = new SkinnedMesh()\n      mesh.material = material\n      mesh.bind(parent.skeleton, parent.bindMatrix)\n      group.add(mesh)\n    }\n    else if (parent.isInstancedMesh) {\n      mesh = new InstancedMesh(parent.geometry, material as Material, parent.count)\n      mesh.instanceMatrix = parent.instanceMatrix\n      group.add(mesh)\n    }\n    else {\n      mesh = new Mesh()\n      mesh.material = material\n      group.add(mesh)\n    }\n    mesh.geometry = props.angle ? toCreasedNormals(parent.geometry, props.angle) : parent.geometry\n  }\n}\n\nfunction updateMaterial() {\n  material.side = BackSide\n  material.transparent = props.transparent\n  material.thickness = props.thickness\n  material.color = normalizeColor(props.color)\n  material.opacity = props.opacity\n  material.size = contextSize\n  material.screenspace = props.screenspace\n  material.toneMapped = props.toneMapped\n  material.polygonOffset = props.polygonOffset\n  material.polygonOffsetFactor = props.polygonOffsetFactor\n}\n\nconst sizes = useTres().sizes\nwatch(() => [sizes.width.value, sizes.height.value], ([w, h]) => {\n  contextSize.set(w, h)\n})\nwatch(() => [props.angle], () => {\n  if (groupRef.value) { updateMesh(groupRef.value) }\n})\nwatch(() => [props.transparent, props.thickness, props.color, props.opacity, contextSize, props.screenspace, props.toneMapped, props.polygonOffset, props.polygonOffsetFactor], () => updateMaterial(), { immediate: true },\n)\n\nonMounted(() => updateMesh(groupRef.value))\n\nonUnmounted(() => {\n  const mesh = groupRef.value?.children[0] as Mesh\n  if (mesh) {\n    mesh.geometry.dispose()\n    material.dispose()\n    mesh.removeFromParent()\n  }\n})\n</script>\n\n<template>\n  <TresGroup ref=\"groupRef\" />\n</template>\n"
  },
  {
    "path": "src/core/abstractions/PositionalAudio.vue",
    "content": "<script setup lang=\"ts\">\nimport { useLoader, useTresContext } from '@tresjs/core'\nimport { AudioListener, AudioLoader, Box3 } from 'three'\nimport { PositionalAudioHelper } from 'three-stdlib'\nimport { onBeforeUnmount, onMounted, shallowReactive, shallowRef, toRefs, watch } from 'vue'\nimport type { Material, Object3D, PositionalAudio } from 'three'\n\n// TODO: Add & Dynamize : setRolloffFactor 'FLOAT' from https://threejs.org/docs/index.html?q=posi#api/en/audio/PositionalAudio.setRolloffFactor\n// TODO: Add & Dynamize : setMaxDistance 'FLOAT' from https://threejs.org/docs/index.html?q=posi#api/en/audio/PositionalAudio.setMaxDistance\n// TODO: Add & Dynamize : setDistanceModel 'STRING' from https://threejs.org/docs/index.html?q=posi#api/en/audio/PositionalAudio.setDistanceModel\n\nexport interface PositionalAudioProps {\n  ready: boolean\n  url: string\n  distance?: number\n  helper?: boolean\n  loop?: boolean\n  autoplay?: boolean\n  innerAngle?: number\n  outerAngle?: number\n  outerGain?: number\n}\n\nconst props = withDefaults(defineProps<PositionalAudioProps>(), {\n  ready: false,\n  helper: false,\n  distance: 2,\n  loop: false,\n  autoplay: false,\n  innerAngle: 360,\n  outerAngle: 360,\n  outerGain: 0,\n})\n\nconst emit = defineEmits(['isPlaying'])\n\nconst { ready, url, distance, helper, loop, autoplay, innerAngle, outerAngle, outerGain } = toRefs(props)\n\nconst { state: buffer } = useLoader<AudioBuffer | AudioBuffer[]>(AudioLoader, url.value)\n\nconst { camera } = useTresContext()\n\nconst positionalAudioRef = shallowRef<PositionalAudio | null>(null)\nconst positionalAudioHelperRef = shallowRef<PositionalAudioHelper | null>(null)\n\nconst listener = shallowReactive<AudioListener>(new AudioListener())\n\nconst playAudio = () => {\n  if (positionalAudioRef?.value?.isPlaying) { return }\n\n  positionalAudioRef?.value?.play()\n  emit('isPlaying', positionalAudioRef?.value?.isPlaying)\n}\n\nconst pauseAudio = () => {\n  if (!positionalAudioRef?.value?.isPlaying) { return }\n\n  positionalAudioRef.value.pause()\n  emit('isPlaying', positionalAudioRef?.value?.isPlaying)\n}\n\nconst stopAudio = () => {\n  if (!positionalAudioRef.value) { return }\n\n  positionalAudioRef.value.stop()\n  emit('isPlaying', positionalAudioRef?.value?.isPlaying)\n}\n\nconst disposeAudio = () => {\n  if (!positionalAudioRef?.value) { return }\n\n  stopAudio()\n\n  const audio = positionalAudioRef.value\n\n  if (audio.source) {\n    audio.disconnect()\n  }\n}\n\nconst disposeHelper = () => {\n  if (!positionalAudioRef?.value || !positionalAudioHelperRef?.value) { return }\n\n  positionalAudioHelperRef?.value?.dispose()\n  positionalAudioRef?.value?.remove(positionalAudioHelperRef?.value)\n}\n\nconst updatePositionalAudio = () => {\n  if (!positionalAudioRef.value || !buffer.value) { return }\n\n  const audioBuffer = Array.isArray(buffer.value) ? buffer.value[0] : buffer.value\n  positionalAudioRef.value.setBuffer(audioBuffer)\n  positionalAudioRef.value.setRefDistance(distance.value)\n  positionalAudioRef.value.setLoop(loop.value)\n  positionalAudioRef.value.setDirectionalCone(innerAngle.value, outerAngle.value, outerGain.value)\n\n  positionalAudioHelperRef?.value?.update()\n\n  // Small hack to solve the visibility problem of material[0] inside the positionalAudioHelperRef function update()\n  // https://github.com/mrdoob/three.js/blob/ef80ac74e6716a50104a57d8add6c8a950bff8d7/examples/jsm/helpers/PositionalAudioHelper.js#L94C49-L94C57\n  if (positionalAudioHelperRef?.value) {\n    const material = (positionalAudioHelperRef.value.material as Material[])[0]\n    const materialVisible = material.visible\n\n    if (!materialVisible && outerAngle.value !== innerAngle.value) {\n      material.visible = true\n    }\n  }\n}\n\nconst createHelper = () => {\n  updatePositionalAudio()\n\n  const parent = positionalAudioRef.value?.parent\n  const boxParent = new Box3().setFromObject(parent as Object3D)\n  const depthParent = (boxParent.max.z - boxParent.min.z) * 2\n\n  positionalAudioHelperRef.value = new PositionalAudioHelper(positionalAudioRef.value as PositionalAudio, depthParent, 32, 16)\n  positionalAudioRef?.value?.add(positionalAudioHelperRef.value)\n  positionalAudioHelperRef.value.update()\n}\n\nconst dispose = () => {\n  camera.activeCamera.value?.remove(listener)\n\n  disposeAudio()\n  disposeHelper()\n}\n\ndefineExpose({\n  instance: positionalAudioRef,\n  play: playAudio,\n  stop: stopAudio,\n  pause: pauseAudio,\n  dispose,\n})\n\nwatch(positionalAudioRef, () => {\n  if (!positionalAudioRef?.value) { return }\n\n  if (helper.value) { createHelper() }\n  if (ready.value && autoplay) { playAudio() }\n})\n\nwatch(helper, () => {\n  if (helper.value) {\n    createHelper()\n  }\n  else {\n    disposeHelper()\n  }\n})\n\nwatch(ready, () => {\n  if (ready.value) { updatePositionalAudio() }\n\n  if (autoplay.value && ready.value) { playAudio() }\n  if (!autoplay.value && ready.value) { stopAudio() }\n})\n\nwatch([distance, loop, buffer, innerAngle, outerAngle, outerGain, autoplay], () => {\n  updatePositionalAudio()\n})\n\nonMounted(() => {\n  camera.activeCamera.value?.add(listener)\n})\n\nonBeforeUnmount(() => {\n  dispose()\n})\n</script>\n\n<template>\n  <TresPositionalAudio\n    ref=\"positionalAudioRef\"\n    :args=\"[listener]\"\n    v-bind=\"$attrs\"\n  />\n</template>\n"
  },
  {
    "path": "src/core/abstractions/Reflector.vue",
    "content": "<script lang=\"ts\" setup>\nimport { useTres } from '@tresjs/core'\nimport { Reflector } from 'three-stdlib'\nimport { shallowRef, toRefs, watch } from 'vue'\nimport type { TresColor } from '@tresjs/core'\n\nexport interface ReflectorProps {\n  /**\n   * The color of the reflector.\n   *\n   * @default '#333'\n   * @type {TresColor}\n   * @memberof ReflectorProps\n   *\n   */\n  color?: TresColor\n  /**\n   * The textureWidth of the internal WebGLRenderTarget.\n   *\n   * @default window.innerWidth\n   * @type {number}\n   * @memberof ReflectorProps\n   *\n   */\n  textureWidth?: number\n  /**\n   * The textureHeight of the internal WebGLRenderTarget.\n   *\n   * @default window.innerHeight\n   * @type {number}\n   * @memberof ReflectorProps\n   *\n   */\n  textureHeight?: number\n  /**\n   * The clipBias.\n   *\n   * @default 0\n   * @type {number}\n   * @memberof ReflectorProps\n   *\n   */\n  clipBias?: number\n  /**\n   * The multisample.\n   *\n   * @default 4\n   * @type {number}\n   * @memberof ReflectorProps\n   *\n   */\n  multisample?: number\n  /**\n   * Custom shader.\n   *\n   * @default Reflector.ReflectorShader\n   * @type {object}\n   * @memberof ReflectorProps\n   *\n   */\n  shader?: object\n}\n\nconst props = withDefaults(defineProps<ReflectorProps>(), {\n  color: '#333',\n  textureWidth: 512,\n  textureHeight: 512,\n  clipBias: 0,\n  multisample: 4,\n  // @ts-expect-error: `ReflectorShader` is not present in imported type but is present here:\n  // https://github.com/mrdoob/three.js/blob/dev/examples/jsm/objects/Reflector.js#L32\n  shader: Reflector.ReflectorShader,\n})\n\nconst { extend, invalidate } = useTres()\n\nconst reflectorRef = shallowRef<Reflector>()\n\nextend({ Reflector })\n\nconst { color, textureWidth, textureHeight, clipBias, multisample, shader }\n  = toRefs(props)\n\nwatch(props, () => {\n  invalidate()\n})\n\ndefineExpose({\n  instance: reflectorRef,\n})\n</script>\n\n<template>\n  <TresReflector\n    ref=\"reflectorRef\"\n    :args=\"[undefined, { textureWidth, textureHeight, clipBias, multisample, shader }]\"\n    :material-uniforms-color-value=\"color\"\n  >\n    <slot>\n      <TresPlaneGeometry :args=\"[5, 5]\" />\n    </slot>\n  </TresReflector>\n</template>\n"
  },
  {
    "path": "src/core/abstractions/ScreenSizer.vue",
    "content": "<script setup lang=\"ts\">\nimport { Vector3 } from 'three'\nimport { calculateScaleFactor } from '../../utils/calculateScaleFactor'\nimport { computed, shallowRef } from 'vue'\nimport { useLoop, useTres } from '@tresjs/core'\n\nconst worldPos = new Vector3()\nconst outerRef = shallowRef()\nconst innerRef = shallowRef()\n\nconst sizes = useTres().sizes\nconst size = computed(() => ({ width: sizes.width.value, height: sizes.height.value }))\n\nuseLoop().onBeforeRender(({ camera }) => {\n  const obj = innerRef.value\n  if (!obj || !camera.value) { return }\n  const sf = calculateScaleFactor(obj.getWorldPosition(worldPos), 1, camera.value, size.value)\n  obj.scale.setScalar(sf)\n})\n\ndefineExpose({ instance: outerRef })\n</script>\n\n<template>\n  <TresObject3D ref=\"outerRef\">\n    <TresObject3D ref=\"innerRef\">\n      <slot></slot>\n    </TresObject3D>\n  </TresObject3D>\n</template>\n"
  },
  {
    "path": "src/core/abstractions/ScreenSpace.vue",
    "content": "<script setup lang=\"ts\">\nimport { shallowRef } from 'vue'\nimport { useLoop } from '@tresjs/core'\n\nexport interface ScreenSpaceProps {\n  depth?: number\n}\n\nwithDefaults(defineProps<ScreenSpaceProps>(), {\n  depth: -1,\n})\n\nconst outerRef = shallowRef()\n\nuseLoop().onBeforeRender(({ camera }) => {\n  if (outerRef.value && camera.value) {\n    outerRef.value.quaternion.copy(camera.value.quaternion)\n    outerRef.value.position.copy(camera.value.position)\n  }\n})\n\ndefineExpose({ instance: outerRef })\n</script>\n\n<template>\n  <TresGroup ref=\"outerRef\">\n    <TresGroup :position-z=\"-depth\">\n      <slot></slot>\n    </TresGroup>\n  </TresGroup>\n</template>\n"
  },
  {
    "path": "src/core/abstractions/Text3D.vue",
    "content": "<script setup lang=\"ts\">\nimport { useTres } from '@tresjs/core'\nimport { FontLoader, TextGeometry } from 'three-stdlib'\nimport { computed, shallowRef, toRefs, toValue, useSlots, watch, watchEffect } from 'vue'\nimport type { Slots } from 'vue'\nimport type { TextGeometryParameters } from 'three-stdlib'\n\nexport interface Glyph {\n  _cachedOutline: string[]\n  ha: number\n  o: string\n}\n\nexport interface FontData {\n  boundingBox: {\n    yMax: number\n    yMin: number\n  }\n  familyName: string\n  glyphs: {\n    [k: string]: Glyph\n  }\n  resolution: number\n  underlineThickness: number\n}\n\nexport interface Text3DProps {\n  /**\n   *\n   *  The JSON font to use for the text.\n   *  Text3D requires fonts in JSON format generated through [typeface.json](http://gero3.github.io/facetype.js)\n   *\n   * @type {(FontData | string)}\n   * @memberof Text3DProps\n   * @see https://threejs.org/docs/index.html?q=TEXT#examples/en/geometries/TextGeometry\n   */\n  font: FontData | string\n  /**\n   * The text to display.\n   *\n   * @type {string}\n   * @memberof Text3DProps\n   */\n  text?: string\n  /**\n   * The size of the text.\n   *\n   * @type {number}\n   * @memberof Text3DProps\n   * @default 0.5\n   */\n  size?: number\n  /**\n   * The height of the text.\n   *\n   * @type {number}\n   * @memberof Text3DProps\n   * @default 0.2\n   */\n  height?: number\n  /**\n   * The curve segments of the text.\n   *\n   * @type {number}\n   * @memberof Text3DProps\n   * @default 5\n   */\n  curveSegments?: number\n  /**\n   * Turn on bevel\n   *\n   * @type {boolean}\n   * @memberof Text3DProps\n   * @default true\n   */\n  bevelEnabled?: boolean\n  /**\n   * How deep into text bevel goes.\n   *\n   * @type {number}\n   * @memberof Text3DProps\n   * @default 0.05\n   */\n  bevelThickness?: number\n  /**\n   * How far from text outline is bevel.\n   *\n   * @type {number}\n   * @memberof Text3DProps\n   * @default 0.02\n   */\n  bevelSize?: number\n  /**\n   * How far from text outline is bevel.\n   *\n   * @type {number}\n   * @memberof Text3DProps\n   * @default 0\n   */\n  bevelOffset?: number\n  /**\n   * How many bevel segments.\n   *\n   * @type {number}\n   * @memberof Text3DProps\n   * @default 4\n   */\n  bevelSegments?: number\n  /**\n   * Whether to center the text.\n   *\n   * @type {boolean}\n   * @memberof Text3DProps\n   * @default false\n   */\n  center?: boolean\n  /**\n   * Whether to update the text.\n   *\n   * @type {boolean}\n   * @memberof Text3DProps\n   * @default false\n   */\n  needUpdates?: boolean\n}\n\nconst props = withDefaults(defineProps<Text3DProps>(), {\n  size: 0.5,\n  height: 0.2,\n  curveSegments: 5,\n  bevelEnabled: true,\n  bevelThickness: 0.05,\n  bevelSize: 0.02,\n  bevelOffset: 0,\n  bevelSegments: 4,\n  center: false,\n  needUpdates: false,\n})\n\nconst {\n  center,\n  font,\n  text,\n  needUpdates,\n  size,\n  height,\n  curveSegments,\n  bevelEnabled,\n  bevelThickness,\n  bevelSize,\n  bevelOffset,\n  bevelSegments,\n} = toRefs(props)\n\nconst { extend, invalidate } = useTres()\n\nwatch(props, () => {\n  invalidate()\n})\n\nextend({ TextGeometry })\n\nconst loader = new FontLoader()\n\nconst slots: Slots = useSlots()\n\nconst localText = computed((): string => {\n  if (text?.value) { return text.value }\n  else if (slots.default) { return (slots.default()[0].children as string)?.trim() }\n  return needUpdates.value ? '' : 'TresJS'\n})\n\nconst text3DRef = shallowRef()\n\ndefineExpose({\n  instance: text3DRef,\n})\n\nconst localFont = await new Promise((resolve, reject) => {\n  try {\n    if (typeof font.value === 'string') {\n      loader.load(font.value, (font) => {\n        resolve(font)\n      })\n    }\n    else {\n      resolve(font.value)\n    }\n  }\n  catch (error) {\n    reject(console.error('cientos', error))\n  }\n})\n\nconst textOptions = computed(() => ({\n  font: localFont,\n  size: toValue(size),\n  height: toValue(height),\n  curveSegments: toValue(curveSegments),\n  bevelEnabled: toValue(bevelEnabled),\n  bevelThickness: toValue(bevelThickness),\n  bevelSize: toValue(bevelSize),\n  bevelOffset: toValue(bevelOffset),\n  bevelSegments: toValue(bevelSegments),\n}))\n\nwatchEffect(() => {\n  if (text3DRef.value && needUpdates.value) {\n    text3DRef.value.geometry.dispose()\n    text3DRef.value.geometry = new TextGeometry(localText.value, textOptions.value as TextGeometryParameters)\n    if (center.value) {\n      text3DRef.value.geometry.center()\n    }\n  }\n})\n</script>\n\n<template>\n  <TresMesh\n    v-if=\"font\"\n    ref=\"text3DRef\"\n  >\n    <TresTextGeometry\n      v-if=\"localText\"\n      :args=\"[localText, textOptions]\"\n      :center=\"center\"\n    />\n    <slot></slot>\n  </TresMesh>\n</template>\n"
  },
  {
    "path": "src/core/abstractions/index.ts",
    "content": "import AnimatedSprite from './AnimatedSprite/component.vue'\nimport CubeCamera from './CubeCamera/component.vue'\nimport Billboard from './Billboard.vue'\nimport { GlobalAudio } from './GlobalAudio'\nimport GradientTexture from './GradientTexture.vue'\nimport Image from './Image/component.vue'\nimport Lensflare from './Lensflare/component.vue'\nimport Levioso from './Levioso.vue'\nimport MarchingCube from './MarchingCubes/MarchingCube.vue'\nimport MarchingCubes from './MarchingCubes/MarchingCubes.vue'\nimport MarchingPlane from './MarchingCubes/MarchingPlane.vue'\nimport Mask from './Mask/component.vue'\nimport MouseParallax from './MouseParallax.vue'\nimport Outline from './Outline/component.vue'\nimport PositionalAudio from './PositionalAudio.vue'\nimport Reflector from './Reflector.vue'\nimport ScreenSpace from './ScreenSpace.vue'\nimport Text3D from './Text3D.vue'\nimport { useAnimations } from './useAnimations'\nimport { useMask } from './Mask/useMask'\nimport Fbo from './useFBO/component.vue'\nimport Sampler from './useSurfaceSampler/component.vue'\nimport ScreenSizer from './ScreenSizer.vue'\nimport Edges from './Edges.vue'\n\nexport * from '../staging/useEnvironment'\nexport * from './useFBO/'\nexport * from './useSurfaceSampler'\nexport {\n  AnimatedSprite,\n  Billboard,\n  CubeCamera,\n  Edges,\n  Fbo,\n  GlobalAudio,\n  GradientTexture,\n  Image,\n  Lensflare,\n  Levioso,\n  MarchingCube,\n  MarchingCubes,\n  MarchingPlane,\n  Mask,\n  MouseParallax,\n  Outline,\n  PositionalAudio,\n  Reflector,\n  Sampler,\n  ScreenSizer,\n  ScreenSpace,\n  Text3D,\n  useAnimations,\n  useMask,\n}\n"
  },
  {
    "path": "src/core/abstractions/useAnimations.ts",
    "content": "import { useLoop } from '@tresjs/core'\nimport { AnimationMixer } from 'three'\nimport { computed, ref, shallowReactive, unref, watch } from 'vue'\nimport type { AnimationAction, AnimationClip, Object3D } from 'three'\nimport type { MaybeRef, Ref } from 'vue'\n\n/**\n * Creates an AnimationMixer and returns it.\n *\n * @export\n * @template T\n * @param {T[]} animations\n * @param {(Scene | Ref<Object3D | undefined | null>)} [modelRef]\n * @return {*}\n */\nexport function useAnimations<T extends AnimationClip>(\n  animations: MaybeRef<T[]>,\n  modelRef?: MaybeRef<Object3D | undefined | null>,\n  options?: {\n    manualUpdate?: boolean\n  },\n) {\n  const reference: Ref<Object3D> = ref(modelRef) as Ref<Object3D>\n\n  const mixer = computed(() => new AnimationMixer(reference.value))\n\n  const actions = shallowReactive<{ [key: string]: AnimationAction | undefined }>({})\n\n  const setupActions = () => {\n    const items = unref(animations)\n    if (items && items.length > 0) {\n      Object.keys(actions).forEach(key => delete actions[key])\n      items.forEach((animation: T) => {\n        const action = mixer.value.clipAction(animation, reference.value)\n        actions[animation.name] = action\n      })\n    }\n  }\n\n  watch(animations, setupActions, { deep: true, immediate: true })\n\n  watch(reference, (newRef) => {\n    if (newRef) {\n      mixer.value.uncacheRoot(reference.value)\n      setupActions()\n    }\n  })\n\n  if (!options?.manualUpdate) {\n    const { onBeforeRender } = useLoop()\n\n    onBeforeRender(({ delta }) => {\n      mixer.value.update(delta)\n    })\n  }\n\n  return {\n    actions,\n    mixer,\n  }\n}\n"
  },
  {
    "path": "src/core/abstractions/useFBO/component.vue",
    "content": "<script setup lang=\"ts\">\nimport { useFBO } from '.'\nimport type { FboOptions } from '.'\n\nconst props = withDefaults(defineProps<FboOptions>(), {\n  depth: false,\n  settings: undefined,\n  autoRender: true,\n})\n\nconst target = useFBO(props)\n\ndefineExpose({\n  instance: target,\n})\n</script>\n"
  },
  {
    "path": "src/core/abstractions/useFBO/index.ts",
    "content": "import { useLoop, useTres } from '@tresjs/core'\nimport { DepthTexture, FloatType, HalfFloatType, LinearFilter, WebGLRenderTarget } from 'three'\nimport { isReactive, onBeforeUnmount, reactive, ref, toRefs, watch } from 'vue'\nimport type { RenderTargetOptions } from 'three'\nimport type { Ref } from 'vue'\n\nexport interface FboOptions {\n  /*\n   * The width of the frame buffer object. Defaults to the width of the canvas.\n   *\n   * @type {number}\n   * @memberof FboProps\n   */\n  width?: number\n\n  /*\n   * The height of the frame buffer object. Defaults to the height of the canvas.\n   *\n   * @type {number}\n   * @memberof FboProps\n   */\n  height?: number\n\n  /*\n   * If set, the scene depth will be rendered into buffer.depthTexture.\n   *\n   * @default false\n   * @type {boolean}\n   * @memberof FboProps\n   */\n  depth?: boolean\n\n  /*\n   * Additional settings for the render target.\n   * See https://threejs.org/docs/#api/en/renderers/WebGLRenderTarget for more information.\n   *\n   * @default {}\n   * @type {RenderTargetOptions}\n   * @memberof FboProps\n   */\n  settings?: RenderTargetOptions\n\n  /**\n   * Whether to automatically render the FBO on the default scene.\n   *\n   *  @default true\n   *  @type {boolean}\n   *  @memberof FboProps\n   */\n  autoRender?: boolean\n}\n\nexport function useFBO(options: FboOptions) {\n  const target: Ref<WebGLRenderTarget | null> = ref(null)\n\n  const { height, width, settings, depth, autoRender = ref(true) } = isReactive(options) ? toRefs(options) : toRefs(reactive(options))\n\n  const { onBeforeRender } = useLoop()\n  const { camera, renderer, scene, sizes, invalidate } = useTres()\n\n  watch(() => [width?.value, sizes.width.value, height?.value, sizes.height.value], () => {\n    target.value?.dispose()\n\n    target.value = new WebGLRenderTarget(width?.value || sizes.width.value, height?.value || sizes.height.value, {\n      minFilter: LinearFilter,\n      magFilter: LinearFilter,\n      type: HalfFloatType,\n      ...settings?.value,\n    })\n\n    if (depth?.value) {\n      target.value.depthTexture = new DepthTexture(\n        width?.value || sizes.width.value,\n        height?.value || sizes.height.value,\n        FloatType,\n      )\n    }\n\n    invalidate()\n  }, { immediate: true })\n\n  onBeforeRender(() => {\n    if (autoRender.value) {\n      renderer.setRenderTarget(target.value)\n      renderer.clear()\n      if (camera.value) {\n        renderer.render(scene.value, camera.value)\n      }\n\n      renderer.setRenderTarget(null)\n    }\n  }, Number.POSITIVE_INFINITY)\n\n  onBeforeUnmount(() => {\n    target.value?.dispose()\n  })\n\n  return target\n}\n"
  },
  {
    "path": "src/core/abstractions/useSurfaceSampler/component.vue",
    "content": "<script setup lang=\"ts\">\nimport { useTres } from '@tresjs/core'\nimport { ref, watch, watchEffect } from 'vue'\nimport type { InstancedMesh, Mesh } from 'three'\nimport { useSurfaceSampler } from '.'\nimport type { useSurfaceSamplerProps } from '.'\n\nconst props = defineProps<useSurfaceSamplerProps>()\n\nconst samplerRef = ref()\nconst instancedRef = ref()\nconst meshToSampleRef = ref()\n\nconst { invalidate } = useTres()\n\nwatch(props, () => {\n  invalidate()\n})\n\n// TODO: refactor to use watch instead.\nwatchEffect(() => {\n  instancedRef.value = props.instanceMesh ?? samplerRef.value?.children.find((c: any) => Object.prototype.hasOwnProperty.call(c, 'instanceMatrix')) as InstancedMesh\n\n  meshToSampleRef.value = props.mesh ?? (samplerRef.value?.children.find((c: any) => c.type === 'Mesh') as Mesh)\n\n  useSurfaceSampler(meshToSampleRef.value, props.count, instancedRef.value, props.weight, props.transform)\n})\n\ndefineExpose({\n  samplerRef,\n})\n</script>\n\n<template>\n  <TresGroup ref=\"samplerRef\">\n    <slot></slot>\n  </TresGroup>\n</template>\n"
  },
  {
    "path": "src/core/abstractions/useSurfaceSampler/index.ts",
    "content": "import {\n  Color,\n  InterleavedBuffer,\n  Object3D,\n  Vector3,\n} from 'three'\nimport { MeshSurfaceSampler } from 'three-stdlib'\nimport { ref } from 'vue'\nimport type { InstancedMesh, Mesh, Object3DEventMap } from 'three'\nimport type { TresObject } from '@tresjs/core'\n\nexport interface useSurfaceSamplerProps {\n  /*\n   * A function that can be .\n   *\n   * @type {function}\n   * @memberof useSamplerProps\n   */\n  transform?: TransformFn\n  /*\n   * Specifies a vertex attribute to be used as a weight when sampling from the surface.\n   *\n   * @type {string}\n   * @memberof useSamplerProps\n   */\n  weight?: string\n  /*\n   * Number of samples.\n   *\n   * @type {number}\n   * @memberof useSamplerProps\n   */\n  count?: number\n  /*\n   * Surface mesh from which to sample.\n   *\n   * @type {Mesh}\n   * @memberof useSamplerProps\n   */\n  mesh?: Mesh\n  /*\n   * Instanced mesh to scatter.\n   *\n   * @type {InstancedMesh}\n   * @memberof useSamplerProps\n   */\n  instanceMesh?: InstancedMesh | null\n}\n\ninterface SamplePayload {\n  /**\n   * The position of the sample.\n   */\n  position: Vector3\n  /**\n   * The normal of the mesh at the sampled position.\n   */\n  normal: Vector3\n  /**\n   * The vertex color of the mesh at the sampled position.\n   */\n  color: Color\n}\n\ntype TransformPayload = SamplePayload & {\n  /**\n   * The dummy object used to transform each instance.\n   * This object's matrix will be updated after transforming & it will be used\n   * to set the instance's matrix.\n   */\n  dummy: TresObject\n  /**\n   * The mesh that's initially passed to the sampler.\n   * Use this if you need to apply transforms from your mesh to your instances\n   * or if you need to grab attributes from the geometry.\n   */\n  sampledMesh: Mesh\n}\n\nexport type TransformFn = (payload: TransformPayload, i: number) => void\n\nexport const useSurfaceSampler = (\n  mesh: Mesh,\n  count: number = 16,\n  instanceMesh?: InstancedMesh | null,\n  weight?: string,\n  transform?: TransformFn,\n) => {\n  const arr = new Float32Array(count * 16)\n  const buffer = ref(new InterleavedBuffer(arr, 16))\n\n  const updateBuffer = () => {\n    if (!mesh) { return }\n\n    const sampler = new MeshSurfaceSampler(mesh)\n\n    if (weight) {\n      sampler.setWeightAttribute(weight)\n    }\n    sampler.build()\n\n    const position = new Vector3()\n    const normal = new Vector3()\n    const color = new Color()\n    const dummy = new Object3D<Object3DEventMap>() as TresObject\n\n    mesh.updateMatrixWorld(true)\n\n    for (let i = 0; i < count; i++) {\n      sampler.sample(position, normal, color)\n\n      if (typeof transform === 'function') {\n        transform(\n          {\n            dummy,\n            sampledMesh: mesh,\n            position,\n            normal,\n            color,\n          },\n          i,\n        )\n      }\n      else {\n        dummy.position.copy(position)\n      }\n      dummy.updateMatrix()\n\n      if (instanceMesh) {\n        instanceMesh.setMatrixAt(i, dummy.matrix)\n      }\n      dummy.matrix.toArray(buffer.value.array, i * 16)\n    }\n    if (instanceMesh) {\n      instanceMesh.instanceMatrix.needsUpdate = true\n    }\n\n    buffer.value.needsUpdate = true\n  }\n\n  updateBuffer()\n\n  return { buffer }\n}\n"
  },
  {
    "path": "src/core/controls/CameraControls.vue",
    "content": "<script lang=\"ts\" setup>\nimport { useLoop, useTres } from '@tresjs/core'\nimport { useEventListener } from '@vueuse/core'\nimport CameraControls from 'camera-controls'\nimport {\n  Box3,\n  MathUtils,\n  Matrix4,\n  Quaternion,\n  Raycaster,\n  Sphere,\n  Spherical,\n  Vector2,\n  Vector3,\n  Vector4,\n} from 'three'\nimport { computed, onUnmounted, shallowRef, toRefs, watch, watchEffect } from 'vue'\nimport type { TresControl } from '@tresjs/core'\nimport type {\n  Camera,\n  Object3D,\n  OrthographicCamera,\n  PerspectiveCamera,\n} from 'three'\nimport { isOrthographicCamera, isPerspectiveCamera } from '../../utils/types'\n\nexport interface CameraControlsProps {\n  /**\n   * Whether to make this the default controls.\n   *\n   * @default false\n   * @type {boolean}\n   * @memberof CameraControlsProps\n   */\n  makeDefault?: boolean\n\n  /**\n   * The camera to control.\n   *\n   * @type {PerspectiveCamera | OrthographicCamera}\n   * @memberof CameraControlsProps\n   */\n  camera?: PerspectiveCamera | OrthographicCamera\n\n  /**\n   * The dom element to listen to.\n   *\n   * @type {HTMLElement}\n   * @memberof CameraControlsProps\n   */\n  domElement?: HTMLElement\n\n  /**\n   * Minimum vertical angle in radians.\n   * The angle has to be between `0` and `.maxPolarAngle` inclusive.\n   *\n   * @default 0\n   * @type {number}\n   * @memberof CameraControlsProps\n   */\n  minPolarAngle?: number\n\n  /**\n   * Maximum vertical angle in radians.\n   * The angle has to be between `.maxPolarAngle` and `Math.PI` inclusive.\n   *\n   * @default Math.PI\n   * @type {number}\n   * @memberof CameraControlsProps\n   */\n  maxPolarAngle?: number\n\n  /**\n   * Minimum horizontal angle in radians.\n   * The angle has to be less than `.maxAzimuthAngle`.\n   *\n   * @default -Infinity\n   * @type {number}\n   * @memberof CameraControlsProps\n   */\n  minAzimuthAngle?: number\n\n  /**\n   * Maximum horizontal angle in radians.\n   * The angle has to be greater than `.minAzimuthAngle`.\n   *\n   * @default Infinity\n   * @type {number}\n   * @memberof CameraControlsProps\n   */\n  maxAzimuthAngle?: number\n\n  /**\n   * Current disatnce.\n   *\n   * @type {number}\n   * @memberof CameraControlsProps\n   */\n  distance?: number\n\n  /**\n   * Minimum distance for dolly. The value must be higher than `0`.\n   * PerspectiveCamera only.\n   *\n   * @default Number.EPSILON\n   * @type {number}\n   * @memberof CameraControlsProps\n   */\n  minDistance?: number\n\n  /**\n   * Maximum distance for dolly. The value must be higher than `minDistance`.\n   * PerspectiveCamera only.\n   *\n   * @default Infinity\n   * @type {number}\n   * @memberof CameraControlsProps\n   */\n  maxDistance?: number\n\n  /**\n   * `true` to enable Infinity Dolly for wheel and pinch. Use this with `minDistance` and `maxDistance`.\n   * If the Dolly distance is less (or over) than the `minDistance` (or `maxDistance`),\n   * `infinityDolly` will keep the distance and pushes the target position instead.\n   *\n   * @default false\n   * @type {boolean}\n   * @memberof CameraControlsProps\n   */\n  infinityDolly?: boolean\n\n  /**\n   * Minimum camera zoom.\n   *\n   * @default 0.01\n   * @type {number}\n   * @memberof CameraControlsProps\n   */\n  minZoom?: number\n\n  /**\n   * Maximum camera zoom.\n   *\n   * @default Infinity\n   * @type {number}\n   * @memberof CameraControlsProps\n   */\n  maxZoom?: number\n\n  /**\n   * Approximate time in seconds to reach the target. A smaller value will reach the target faster.\n   *\n   * @default 0.25\n   * @type {number}\n   * @memberof CameraControlsProps\n   */\n  smoothTime?: number\n\n  /**\n   * The smoothTime while dragging.\n   *\n   * @default 0.125\n   * @type {number}\n   * @memberof CameraControlsProps\n   */\n  draggingSmoothTime?: number\n\n  /**\n   * Max transition speed in unit-per-seconds.\n   *\n   * @default Infinity\n   * @type {number}\n   * @memberof CameraControlsProps\n   */\n  maxSpeed?: number\n\n  /**\n   * Speed of azimuth (horizontal) rotation.\n   *\n   * @default 1.0\n   * @type {number}\n   * @memberof CameraControlsProps\n   */\n  azimuthRotateSpeed?: number\n\n  /**\n   * Speed of polar (vertical) rotation.\n   *\n   * @default 1.0\n   * @type {number}\n   * @memberof CameraControlsProps\n   */\n  polarRotateSpeed?: number\n\n  /**\n   * Speed of mouse-wheel dollying.\n   *\n   * @default 1.0\n   * @type {number}\n   * @memberof CameraControlsProps\n   */\n  dollySpeed?: number\n\n  /**\n   * `true` to invert direction when dollying or zooming via drag.\n   *\n   * @default false\n   * @type {boolean}\n   * @memberof CameraControlsProps\n   */\n  dollyDragInverted?: boolean\n\n  /**\n   * Speed of drag for truck and pedestal.\n   *\n   * @default 2.0\n   * @type {number}\n   * @memberof CameraControlsProps\n   */\n  truckSpeed?: number\n\n  /**\n   * `true` to enable Dolly-in to the mouse cursor coords.\n   *\n   * @default false\n   * @type {boolean}\n   * @memberof CameraControlsProps\n   */\n  dollyToCursor?: boolean\n\n  /**\n   * @default false\n   * @type {boolean}\n   * @memberof CameraControlsProps\n   */\n  dragToOffset?: boolean\n\n  /**\n   * The same as `.screenSpacePanning` in three.js's OrbitControls.\n   *\n   * @default false\n   * @type {boolean}\n   * @memberof CameraControlsProps\n   */\n  verticalDragToForward?: boolean\n\n  /**\n   * Friction ratio of the boundary.\n   *\n   * @default 0.0\n   * @type {number}\n   * @memberof CameraControlsProps\n   */\n  boundaryFriction?: number\n\n  /**\n   * Controls how soon the `rest` event fires as the camera slows.\n   *\n   * @default 0.01\n   * @type {number}\n   * @memberof CameraControlsProps\n   */\n  restThreshold?: number\n\n  /**\n   * An array of Meshes to collide with the camera.\n   * Be aware colliderMeshes may decrease performance.\n   * The collision test uses 4 raycasters from the camera since the near plane has 4 corners.\n   *\n   * @default []\n   * @type {Object3D[]}\n   * @memberof CameraControlsProps\n   */\n  colliderMeshes?: Object3D[]\n\n  /**\n   * User's mouse input config.\n   *\n   * | Button to assign        | Options                                                        | Default                                                         |\n   * | ----------------------- | -------------------------------------------------------------- | --------------------------------------------------------------- |\n   * | `mouseButtons.left`     | `ROTATE` \\| `TRUCK` \\| `OFFSET` \\| `DOLLY` \\| `ZOOM` \\| `NONE` | `ROTATE`                                                        |\n   * | `mouseButtons.right`    | `ROTATE` \\| `TRUCK` \\| `OFFSET` \\| `DOLLY` \\| `ZOOM` \\| `NONE` | `TRUCK`                                                         |\n   * | `mouseButtons.wheel` ¹  | `ROTATE` \\| `TRUCK` \\| `OFFSET` \\| `DOLLY` \\| `ZOOM` \\| `NONE` | `DOLLY` for Perspective camera, `ZOOM` for Orthographic camera. |\n   * | `mouseButtons.middle` ² | `ROTATE` \\| `TRUCK` \\| `OFFSET` \\| `DOLLY` \\| `ZOOM` \\| `NONE` | `DOLLY`                                                         |\n   *\n   * 1. Mouse wheel event for scroll \"up/down\", on mac \"up/down/left/right\".\n   * 2. Mouse wheel \"button\" click event.\n   *\n   * > **_NOTE:_** `DOLLY` can't be set when camera is Orthographic.\n   *\n   * @default See description\n   * @memberof CameraControlsProps\n   */\n  mouseButtons?: Partial<CameraControls['mouseButtons']>\n\n  /**\n   * User's touch input config.\n   *\n   * | Fingers to assign | Options                                                                                                                                                                                                                                 | Default                                                                                |\n   * | ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |\n   * | `touches.one`     | `TOUCH_ROTATE` \\| `TOUCH_TRUCK` \\| `TOUCH_OFFSET` \\| `DOLLY` \\| `ZOOM` \\| `NONE`                                                                                                                                                        | `TOUCH_ROTATE`                                                                         |\n   * | `touches.two`     | `TOUCH_DOLLY_TRUCK` \\| `TOUCH_DOLLY_OFFSET` \\| `TOUCH_DOLLY_ROTATE` \\| `TOUCH_ZOOM_TRUCK` \\| `TOUCH_ZOOM_OFFSET` \\| `TOUCH_ZOOM_ROTATE` \\| `TOUCH_DOLLY` \\| `TOUCH_ZOOM` \\| `TOUCH_ROTATE` \\| `TOUCH_TRUCK` \\| `TOUCH_OFFSET` \\| `NONE` | `TOUCH_DOLLY_TRUCK` for Perspective camera, `TOUCH_ZOOM_TRUCK` for Othographic camera. |\n   * | `touches.three`   | `TOUCH_DOLLY_TRUCK` \\| `TOUCH_DOLLY_OFFSET` \\| `TOUCH_DOLLY_ROTATE` \\| `TOUCH_ZOOM_TRUCK` \\| `TOUCH_ZOOM_OFFSET` \\| `TOUCH_ZOOM_ROTATE` \\| `TOUCH_ROTATE` \\| `TOUCH_TRUCK` \\| `TOUCH_OFFSET` \\| `NONE`                                  | `TOUCH_TRUCK`                                                                          |\n   *\n   * > **_NOTE:_** `TOUCH_DOLLY_TRUCK` and `TOUCH_DOLLY` can't be set when camera is Orthographic.\n   *\n   * @default See description\n   * @memberof CameraControlsProps\n   */\n  touches?: Partial<CameraControls['touches']>\n}\n\nconst props = withDefaults(defineProps<CameraControlsProps>(), {\n  makeDefault: false,\n  minPolarAngle: 0,\n  maxPolarAngle: Math.PI,\n  minAzimuthAngle: Number.NEGATIVE_INFINITY,\n  maxAzimuthAngle: Number.POSITIVE_INFINITY,\n  distance: () => useTres().camera.value!.position.z,\n  minDistance: Number.EPSILON,\n  maxDistance: Number.POSITIVE_INFINITY,\n  infinityDolly: false,\n  minZoom: 0.01,\n  maxZoom: Number.POSITIVE_INFINITY,\n  smoothTime: 0.25,\n  draggingSmoothTime: 0.125,\n  maxSpeed: Number.POSITIVE_INFINITY,\n  azimuthRotateSpeed: 1.0,\n  polarRotateSpeed: 1.0,\n  dollySpeed: 1.0,\n  dollyDragInverted: false,\n  truckSpeed: 2.0,\n  dollyToCursor: false,\n  dragToOffset: false,\n  verticalDragToForward: false,\n  boundaryFriction: 0.0,\n  restThreshold: 0.01,\n  colliderMeshes: () => [],\n  mouseButtons: () => getMouseButtons(useTres().camera.value),\n  touches: () => getTouches(useTres().camera.value),\n})\n\nconst emit = defineEmits(['change', 'start', 'end'])\n\nconst {\n  makeDefault,\n  minPolarAngle,\n  maxPolarAngle,\n  minAzimuthAngle,\n  maxAzimuthAngle,\n  distance,\n  minDistance,\n  maxDistance,\n  infinityDolly,\n  minZoom,\n  maxZoom,\n  smoothTime,\n  draggingSmoothTime,\n  maxSpeed,\n  azimuthRotateSpeed,\n  polarRotateSpeed,\n  dollySpeed,\n  dollyDragInverted,\n  truckSpeed,\n  dollyToCursor,\n  dragToOffset,\n  verticalDragToForward,\n  boundaryFriction,\n  restThreshold,\n  colliderMeshes,\n} = toRefs(props)\n\n// allow for tree shaking, only importing required classes\nconst subsetOfTHREE = {\n  Box3,\n  MathUtils: {\n    clamp: MathUtils.clamp,\n  },\n  Matrix4,\n  Quaternion,\n  Raycaster,\n  Sphere,\n  Spherical,\n  Vector2,\n  Vector3,\n  Vector4,\n}\nCameraControls.install({ THREE: subsetOfTHREE })\n\nconst { camera: activeCamera, renderer, extend, controls, invalidate } = useTres()\n\nwatch(props, () => {\n  invalidate()\n})\n\nconst mouseButtons = computed(() => getMouseButtons(\n  props.camera || activeCamera.value,\n  props.mouseButtons,\n))\nconst touches = computed(() => getTouches(\n  props.camera || activeCamera.value,\n  props.touches,\n))\n\nconst controlsRef = shallowRef<TresControl & CameraControls | null>(null)\nextend({ CameraControls })\n\nwatchEffect(() => {\n  addEventListeners()\n  if (controlsRef.value && makeDefault.value) {\n    controls.value = controlsRef.value\n  }\n  else {\n    controls.value = null\n  }\n})\n\nfunction addEventListeners() {\n  useEventListener(controlsRef.value as any, 'update', () => {\n    emit('change', controlsRef.value)\n    invalidate()\n  })\n  useEventListener(controlsRef.value as any, 'controlend', () => emit('end', controlsRef.value))\n  useEventListener(controlsRef.value as any, 'controlstart', () => emit('start', controlsRef.value))\n}\n\nconst { onBeforeRender } = useLoop()\n\nonBeforeRender(({ delta /* invalidate */ }) => {\n  if (controlsRef.value?.enabled) {\n    controlsRef.value?.update(delta)\n    // TODO: comment this until invalidate is back in the loop callback on v5\n    // invalidate()\n  }\n})\n\nonUnmounted(() => {\n  if (controlsRef.value) {\n    controlsRef.value.disconnect()\n  }\n})\n\ndefineExpose({\n  instance: controlsRef,\n})\n</script>\n\n<script lang=\"ts\">\nconst getMouseButtons = (\n  camera?: Camera,\n  mouseButtons?: Partial<CameraControls['mouseButtons']>,\n): CameraControls['mouseButtons'] => ({\n  left: CameraControls.ACTION.ROTATE,\n  middle: CameraControls.ACTION.DOLLY,\n  right: CameraControls.ACTION.TRUCK,\n  wheel: (\n    isPerspectiveCamera(camera)\n      ? CameraControls.ACTION.DOLLY\n      : isOrthographicCamera(camera)\n        ? CameraControls.ACTION.ZOOM\n        : CameraControls.ACTION.NONE\n  ),\n  ...mouseButtons,\n})\n\nconst getTouches = (\n  camera?: Camera,\n  touches?: Partial<CameraControls['touches']>,\n): CameraControls['touches'] => ({\n  one: CameraControls.ACTION.TOUCH_ROTATE,\n  two: (\n    isPerspectiveCamera(camera)\n      ? CameraControls.ACTION.TOUCH_DOLLY_TRUCK\n      : isOrthographicCamera(camera)\n        ? CameraControls.ACTION.TOUCH_ZOOM_TRUCK\n        : CameraControls.ACTION.NONE\n  ),\n  three: CameraControls.ACTION.TOUCH_TRUCK,\n  ...touches,\n})\n\nexport { default as BaseCameraControls } from 'camera-controls'\n</script>\n\n<template>\n  <TresCameraControls\n    v-if=\"(camera || activeCamera) && (domElement || renderer.domElement)\"\n    ref=\"controlsRef\"\n    :min-polar-angle=\"minPolarAngle\"\n    :max-polar-angle=\"maxPolarAngle\"\n    :min-azimuth-angle=\"minAzimuthAngle\"\n    :max-azimuth-angle=\"maxAzimuthAngle\"\n    :distance=\"distance\"\n    :min-distance=\"minDistance\"\n    :max-distance=\"maxDistance\"\n    :infinity-dolly=\"infinityDolly\"\n    :min-zoom=\"minZoom\"\n    :max-zoom=\"maxZoom\"\n    :smooth-time=\"smoothTime\"\n    :dragging-smooth-time=\"draggingSmoothTime\"\n    :max-speed=\"maxSpeed\"\n    :azimuth-rotate-speed=\"azimuthRotateSpeed\"\n    :polar-rotate-speed=\"polarRotateSpeed\"\n    :dolly-speed=\"dollySpeed\"\n    :dolly-drag-inverted=\"dollyDragInverted\"\n    :truck-speed=\"truckSpeed\"\n    :dolly-to-cursor=\"dollyToCursor\"\n    :drag-to-offset=\"dragToOffset\"\n    :vertical-drag-to-forward=\"verticalDragToForward\"\n    :boundary-friction=\"boundaryFriction\"\n    :rest-threshold=\"restThreshold\"\n    :collider-meshes=\"colliderMeshes\"\n    :args=\"[camera || activeCamera, domElement || renderer.domElement]\"\n    :mouse-buttons=\"mouseButtons\"\n    :touches=\"touches\"\n  />\n</template>\n"
  },
  {
    "path": "src/core/controls/Helper/component.vue",
    "content": "<script setup lang=\"ts\">\nimport { shallowRef, watchEffect } from 'vue'\nimport { useHelper } from './useHelper'\nimport type { TresObject } from '@tresjs/core'\n\ntype HelperConstructor = new (...args: any[]) => any\n\nexport interface HelperProps {\n  type: HelperConstructor\n  args?: any[]\n}\n\nconst props = defineProps<HelperProps>()\n\nconst objRef = shallowRef<TresObject>()\nconst parentRef = shallowRef<TresObject>()\n\nwatchEffect(() => {\n  if (objRef.value && objRef.value.parent) {\n    parentRef.value = objRef.value.parent\n  }\n})\n\nuseHelper(parentRef, props.type, ...(props.args) ?? [])\n</script>\n\n<template>\n  <TresObject3D ref=\"objRef\" />\n</template>\n"
  },
  {
    "path": "src/core/controls/Helper/useHelper.ts",
    "content": "import type { Object3D } from 'three'\nimport type { MaybeRefOrGetter } from 'vue'\nimport { onBeforeUnmount, shallowRef, toValue, watchEffect } from 'vue'\nimport type { TresObject } from '@tresjs/core'\nimport { useLoop, useTres } from '@tresjs/core'\n\n// NOTE: Source\n// https://github.com/pmndrs/drei/blob/master/src/core/Helper.tsx\n\ntype HelperType = Object3D & { update: () => void, dispose: () => void }\ntype HelperConstructor = new (...args: any[]) => any\n\nexport function useHelper<T extends HelperConstructor>(\n  object3D: MaybeRefOrGetter<TresObject | null | undefined | false>,\n  helperConstructor: T,\n  ...args: any[]\n) {\n  const helper = shallowRef<HelperType>()\n  const { scene } = useTres()\n\n  let currentHelper: HelperType = undefined!\n\n  watchEffect(() => {\n    if (object3D && toValue(object3D) && helperConstructor) {\n      // eslint-disable-next-line new-cap\n      helper.value = currentHelper = new helperConstructor(toValue(object3D), ...args)\n    }\n\n    if (currentHelper) {\n      // NOTE: Prevent the helpers from blocking rays\n      currentHelper.traverse(child => (child.raycast = () => null))\n      scene.value.add(currentHelper)\n    }\n  })\n\n  onBeforeUnmount(() => {\n    helper.value = undefined\n    scene.value.remove(currentHelper)\n    currentHelper.dispose?.()\n  })\n\n  useLoop().onBeforeRender(() => {\n    helper.value?.update?.()\n  })\n\n  return helper\n}\n"
  },
  {
    "path": "src/core/controls/KeyboardControls.vue",
    "content": "<script setup lang=\"ts\">\nimport { useLoop, useTres } from '@tresjs/core'\nimport { useMagicKeys } from '@vueuse/core'\nimport { Quaternion, Vector3 } from 'three'\nimport { PointerLockControls as PointerLockControlsType } from 'three-stdlib'\nimport { ref, toRefs, watch, watchEffect } from 'vue'\nimport type { Camera } from 'three'\nimport { PointerLockControls } from './index'\n\nexport interface KeyboardControlsProps {\n  /**\n   * Whether to make this the default controls.\n   *\n   * @default true\n   * @type {boolean}\n   * @memberof KeyboardControlsProps\n   * @see https://threejs.org/docs/index.html?q=pointe#examples/en/controls/PointerLockControls\n   */\n  makeDefault?: boolean\n  /**\n   * The camera to control.\n   *\n   * @default false\n   * @type {boolean}\n   * @memberof KeyboardControlsProps\n   * @see https://threejs.org/docs/index.html?q=pointe#examples/en/controls/PointerLockControls\n   */\n  camera?: Camera\n  /**\n   * The dom element to listen to.\n   *\n   * @type {HTMLElement}\n   * @memberof KeyboardControlsProps\n   * @see https://threejs.org/docs/index.html?q=pointe#examples/en/controls/PointerLockControls\n   */\n  domElement?: HTMLElement\n  /**\n   * Indicates the movement speed.\n   * @type {number}\n   * @default 0.2\n   * @memberof KeyboardControlsProps\n   *\n   */\n  moveSpeed?: number\n  /**\n   * The trigger id.\n   *\n   * @type {string}\n   * @memberof KeyboardControlsProps\n   * @see https://threejs.org/docs/index.html?q=pointe#examples/en/controls/PointerLockControls\n   */\n  selector?: string\n}\n\nconst props = withDefaults(defineProps<KeyboardControlsProps>(), {\n  moveSpeed: 0.2,\n  makeDefault: true,\n})\n\nconst emit = defineEmits(['isLock', 'change'])\n\nconst { moveSpeed } = toRefs(props)\n\nconst { camera: activeCamera, controls, renderer, invalidate } = useTres()\n\nwatch(props, () => {\n  invalidate()\n})\n\nconst sidewardMove = ref(0)\nconst forwardMove = ref(0)\n\nconst { KeyW, KeyA, KeyS, KeyD, Up, Down, Left, Right } = useMagicKeys()\n\nwatchEffect(() => {\n  if (KeyA.value || Left.value) { sidewardMove.value = -moveSpeed.value }\n  else if (KeyD.value || Right.value) { sidewardMove.value = moveSpeed.value }\n  else { sidewardMove.value = 0 }\n  if (KeyW.value || Up.value) { forwardMove.value = moveSpeed.value }\n  else if (KeyS.value || Down.value) { forwardMove.value = -moveSpeed.value }\n  else { forwardMove.value = 0 }\n})\n\ndefineExpose({\n  instance: controls,\n})\n\nconst isActive = (isLock: boolean) => emit('isLock', isLock)\n\nconst hasChange = (state: any) => emit('change', state)\n\nconst moveVector = new Vector3()\nconst rotationVector = new Vector3()\nconst tmpQuaternion = new Quaternion()\n\nconst moveForward = (delta: number, movementSpeed: number) => {\n  if (!activeCamera.value?.position && !moveVector) { return }\n  const camera = activeCamera.value\n  const rotMult = delta * 0.001\n  camera?.translateZ(-movementSpeed)\n\n  tmpQuaternion.set(rotationVector.x * rotMult, rotationVector.y * rotMult, rotationVector.z * rotMult, 1).normalize()\n  camera?.quaternion.multiply(tmpQuaternion)\n  if (sidewardMove.value || forwardMove.value) { emit('change', controls.value) }\n}\n\nconst { onBeforeRender } = useLoop()\n\nonBeforeRender(({ delta /* invalidate */ }) => {\n  if (controls.value instanceof PointerLockControlsType && controls.value?.isLocked) {\n    moveForward(delta, forwardMove.value)\n    controls.value.moveRight(sidewardMove.value)\n\n    // TODO: comment this until invalidate is back in the loop callback on v5\n    // invalidate()\n  }\n})\n</script>\n\n<template>\n  <PointerLockControls\n    v-if=\"renderer\"\n    :selector=\"selector\"\n    :make-default=\"makeDefault\"\n    :camera=\"camera || activeCamera\"\n    :dom-element=\"domElement || renderer.domElement\"\n    @is-lock=\"isActive\"\n    @change=\"hasChange\"\n  />\n</template>\n"
  },
  {
    "path": "src/core/controls/MapControls.vue",
    "content": "<script lang=\"ts\" setup>\nimport { useLoop, useTres } from '@tresjs/core'\nimport { useEventListener } from '@vueuse/core'\nimport { MapControls } from 'three-stdlib'\nimport { onUnmounted, shallowRef, toRefs, watch } from 'vue'\nimport type { TresVector3 } from '@tresjs/core'\nimport type { Camera } from 'three'\n\nexport interface MapControlsProps {\n  /**\n   * Whether to make this the default controls.\n   *\n   * @default false\n   * @type {boolean}\n   * @memberof MapControlsProps\n   * @see https://threejs.org/docs/#examples/en/controls/MapControls\n   */\n  makeDefault?: boolean\n  /**\n   * The camera to control.\n   *\n   * @type {Camera}\n   * @memberof MapControlsProps\n   * @see https://threejs.org/docs/#examples/en/controls/MapControls\n   */\n  camera?: Camera\n  /**\n   * The dom element to listen to.\n   *\n   * @type {HTMLElement}\n   * @memberof MapControlsProps\n   * @see https://threejs.org/docs/#examples/en/controls/MapControls\n   */\n  domElement?: HTMLElement\n  /**\n   * The target to orbit around.\n   *\n   * @type {TresVector3}\n   * @memberof OrbitControlsProps\n   * @see https://threejs.org/docs/#examples/en/controls/OrbitControls.target\n   */\n  target?: TresVector3\n  /**\n   * Whether to enable damping (inertia)\n   *\n   * @default false\n   * @type {boolean}\n   * @memberof OrbitControlsProps\n   * @see https://threejs.org/docs/#examples/en/controls/OrbitControls.enableDamping\n   */\n  enableDamping?: boolean\n  /**\n   * The damping inertia used if `.enableDamping` is set to true\n   *\n   * @default 0.05\n   * @type {number}\n   * @memberof OrbitControlsProps\n   * @see https://threejs.org/docs/#examples/en/controls/OrbitControls.dampingFactor\n   */\n  dampingFactor?: number\n  /**\n   * Set to true to automatically rotate around the target.\n   *\n   * @default false\n   * @type {boolean}\n   * @memberof OrbitControlsProps\n   * @see https://threejs.org/docs/#examples/en/controls/OrbitControls.autoRotate\n   */\n  autoRotate?: boolean\n  /**\n   * How fast to rotate around the target if `.autoRotate` is true.\n   *\n   * @default 2\n   * @type {number}\n   * @memberof OrbitControlsProps\n   * @see https://threejs.org/docs/#examples/en/controls/OrbitControls.autoRotateSpeed\n   */\n  autoRotateSpeed?: number\n  /**\n   * Whether to enable panning.\n   *\n   * @default true\n   * @type {boolean}\n   * @memberof OrbitControlsProps\n   * @see https://threejs.org/docs/#examples/en/controls/OrbitControls.enablePan\n   */\n  enablePan?: boolean\n  /**\n   * How fast to pan the camera when the keyboard is used. Default is 7.0 pixels per keypress.\n   *\n   * @default 7.0\n   * @type {number}\n   * @memberof OrbitControlsProps\n   * @see https://threejs.org/docs/#examples/en/controls/OrbitControls.keyPanSpeed\n   */\n  keyPanSpeed?: number\n  /**\n   * This object contains references to the keycodes for controlling camera panning.\n   * Default is the 4 arrow keys.\n   *\n   * @default `{ LEFT: 'ArrowLeft', UP: 'ArrowUp', RIGHT: 'ArrowRight', BOTTOM: 'ArrowDown' }`\n   * @type Record<string, string>\n   * @memberof OrbitControlsProps\n   * @see https://threejs.org/docs/#examples/en/controls/OrbitControls.keys\n   */\n  keys?: Record<string, string>\n  /**\n   * How far you can orbit horizontally, upper limit.\n   * If set, the interval [ min, max ] must be a sub-interval of [ - 2 PI, 2 PI ],\n   * with ( max - min < 2 PI ). Default is Infinity.\n   *\n   * @default Infinity\n   * @type {number}\n   * @memberof OrbitControlsProps\n   * @see https://threejs.org/docs/index.html?q=orbi#examples/en/controls/OrbitControls.maxAzimuthAngle\n   */\n  maxAzimuthAngle?: number\n  /**\n   * How far you can orbit horizontally, lower limit.\n   * If set, the interval [ min, max ] must be a sub-interval of [ - 2 PI, 2 PI ],\n   * with ( max - min < 2 PI ).\n   * Default is - Infinity.\n   *\n   * @default -Infinity\n   * @type {number}\n   * @memberof OrbitControlsProps\n   * @see https://threejs.org/docs/index.html?q=orbi#examples/en/controls/OrbitControls.minAzimuthAngle\n   */\n  minAzimuthAngle?: number\n  /**\n   * How far you can orbit vertically, upper limit.\n   * Range is 0 to Math.PI radians, and default is Math.PI.\n   *\n   * @default Math.PI\n   * @type {number}\n   * @memberof OrbitControlsProps\n   * @see https://threejs.org/docs/index.html?q=orbi#examples/en/controls/OrbitControls.maxPolarAngle\n   */\n  maxPolarAngle?: number\n  /**\n   * How far you can orbit vertically, lower limit.\n   * Range is 0 to Math.PI radians, and default is 0.\n   *\n   * @default 0\n   * @type {number}\n   * @memberof OrbitControlsProps\n   * @see https://threejs.org/docs/index.html?q=orbi#examples/en/controls/OrbitControls.minPolarAngle\n   */\n  minPolarAngle?: number\n  /**\n   * The minimum distance of the camera to the target.\n   * Default is 0.\n   *\n   * @default 0\n   * @type {number}\n   * @memberof OrbitControlsProps\n   * @see https://threejs.org/docs/index.html?q=orbi#examples/en/controls/OrbitControls.minDistance\n   */\n  minDistance?: number\n  /**\n   * The maximum distance of the camera to the target.\n   * Default is Infinity.\n   *\n   * @default Infinity\n   * @type {number}\n   * @memberof OrbitControlsProps\n   * @see https://threejs.org/docs/index.html?q=orbi#examples/en/controls/OrbitControls.maxDistance\n   */\n  maxDistance?: number\n  /**\n   * The minimum field of view angle, in radians.\n   * Default is 0.\n   *\n   * @default 0\n   * @type {number}\n   * @memberof OrbitControlsProps\n   * @see https://threejs.org/docs/index.html?q=orbi#examples/en/controls/OrbitControls.minZoom\n   */\n  minZoom?: number\n  /**\n   * The maximum field of view angle, in radians.\n   * ( OrthographicCamera only ).\n   * Default is Infinity.\n   *\n   * @default Infinity\n   * @type {number}\n   * @memberof OrbitControlsProps\n   * @see https://threejs.org/docs/index.html?q=orbi#examples/en/controls/OrbitControls.maxZoom\n   */\n  maxZoom?: number\n  touches?: {\n    ONE?: number | undefined\n    TWO?: number | undefined\n  }\n  /**\n   * Whether to enable zooming.\n   *\n   * @default true\n   * @type {boolean}\n   * @memberof OrbitControlsProps\n   * @see https://threejs.org/docs/#examples/en/controls/OrbitControls.enableZoom\n   */\n  enableZoom?: boolean\n  /**\n   * How fast to zoom in and out. Default is 1.\n   *\n   * @default 1\n   * @type {number}\n   * @memberof OrbitControlsProps\n   * @see https://threejs.org/docs/#examples/en/controls/OrbitControls.zoomSpeed\n   */\n  zoomSpeed?: number\n  /**\n   * Whether to enable rotating.\n   *\n   * @default true\n   * @type {boolean}\n   * @memberof OrbitControlsProps\n   * @see https://threejs.org/docs/#examples/en/controls/OrbitControls.enableRotate\n   */\n  enableRotate?: boolean\n  /**\n   * How fast to rotate around the target. Default is 1.\n   *\n   * @default 1\n   * @type {number}\n   * @memberof OrbitControlsProps\n   * @see https://threejs.org/docs/#examples/en/controls/OrbitControls.rotateSpeed\n   */\n  rotateSpeed?: number\n}\n\nconst props = withDefaults(defineProps<MapControlsProps>(), {\n  makeDefault: false,\n  autoRotate: false,\n  autoRotateSpeed: 2,\n  enableDamping: true,\n  dampingFactor: 0.05,\n  enablePan: true,\n  keyPanSpeed: 7,\n  maxAzimuthAngle: Number.POSITIVE_INFINITY,\n  minAzimuthAngle: Number.NEGATIVE_INFINITY,\n  maxPolarAngle: Math.PI,\n  minPolarAngle: 0,\n  minDistance: 0,\n  maxDistance: Number.POSITIVE_INFINITY,\n  minZoom: 0,\n  maxZoom: Number.POSITIVE_INFINITY,\n  enableZoom: true,\n  zoomSpeed: 1,\n  enableRotate: true,\n  rotateSpeed: 1,\n})\n\nconst emit = defineEmits(['change', 'start', 'end'])\n\nconst {\n  autoRotate,\n  autoRotateSpeed,\n  enableDamping,\n  dampingFactor,\n  enablePan,\n  keyPanSpeed,\n  maxAzimuthAngle,\n  minAzimuthAngle,\n  maxPolarAngle,\n  minPolarAngle,\n  minDistance,\n  maxDistance,\n  minZoom,\n  maxZoom,\n  enableZoom,\n  zoomSpeed,\n  enableRotate,\n  rotateSpeed,\n} = toRefs(props)\n\nconst { camera: activeCamera, renderer, extend, controls, invalidate } = useTres()\n\nwatch(props, () => {\n  invalidate()\n})\n\nconst controlsRef = shallowRef<MapControls | null>(null)\n\nextend({ MapControls })\n\nwatch(controls, (value) => {\n  if (value && props.makeDefault) {\n    controls.value = value\n  }\n  else {\n    controls.value = null\n  }\n})\n\nfunction onChange() {\n  addEventListeners()\n  invalidate()\n  emit('change', controlsRef.value)\n}\nfunction addEventListeners() {\n  useEventListener(controlsRef.value as any, 'change', onChange)\n  useEventListener(controlsRef.value as any, 'start', () => emit('start', controlsRef.value))\n  useEventListener(controlsRef.value as any, 'end', () => emit('end', controlsRef.value))\n}\nconst { onBeforeRender } = useLoop()\n\nonBeforeRender(() => {\n  if (controlsRef.value && (enableDamping.value || autoRotate.value)) {\n    controlsRef.value.update()\n\n    // TODO: comment this until invalidate is back in the loop callback on v5\n    // invalidate()\n  }\n})\n\nonUnmounted(() => {\n  if (controlsRef.value) {\n    controlsRef.value.dispose()\n  }\n})\n\ndefineExpose({\n  instance: controlsRef,\n})\n</script>\n\n<template>\n  <TresMapControls\n    v-if=\"(camera || activeCamera) && (domElement || renderer.domElement)\"\n    ref=\"controlsRef\"\n    :args=\"[camera || activeCamera, domElement || renderer.domElement]\"\n    :auto-rotate=\"autoRotate\"\n    :auto-rotate-speed=\"autoRotateSpeed\"\n    :enable-damping=\"enableDamping\"\n    :damping-factor=\"dampingFactor\"\n    :enable-pan=\"enablePan\"\n    :key-pan-speed=\"keyPanSpeed\"\n    :keys=\"keys\"\n    :max-azimuth-angle=\"maxAzimuthAngle\"\n    :min-azimuth-angle=\"minAzimuthAngle\"\n    :max-polar-angle=\"maxPolarAngle\"\n    :min-polar-angle=\"minPolarAngle\"\n    :min-distance=\"minDistance\"\n    :max-distance=\"maxDistance\"\n    :min-zoom=\"minZoom\"\n    :max-zoom=\"maxZoom\"\n    :enable-zoom=\"enableZoom\"\n    :zoom-speed=\"zoomSpeed\"\n    :enable-rotate=\"enableRotate\"\n    :rotate-speed=\"rotateSpeed\"\n  />\n</template>\n"
  },
  {
    "path": "src/core/controls/OrbitControls.vue",
    "content": "<script lang=\"ts\" setup>\nimport { useLoop, useTres } from '@tresjs/core'\nimport { useEventListener } from '@vueuse/core'\nimport { MOUSE, TOUCH } from 'three'\nimport { OrbitControls } from 'three-stdlib'\nimport { onUnmounted, shallowRef, toRefs, watch } from 'vue'\nimport type { TresVector3 } from '@tresjs/core'\nimport type { Camera } from 'three'\n\nexport interface OrbitControlsProps {\n  /**\n   * Whether to make this the default controls.\n   *\n   * @default false\n   * @type {boolean}\n   * @memberof OrbitControlsProps\n   */\n  makeDefault?: boolean\n  /**\n   * The camera to control.\n   *\n   * @type {Camera}\n   * @memberof OrbitControlsProps\n   * @see https://threejs.org/docs/#examples/en/controls/OrbitControls.camera\n   */\n  camera?: Camera\n  /**\n   * The dom element to listen to.\n   *\n   * @type {HTMLElement}\n   * @memberof OrbitControlsProps\n   * @see https://threejs.org/docs/#examples/en/controls/OrbitControls.domElement\n   */\n  domElement?: HTMLElement\n  /**\n   * The target to orbit around.\n   *\n   * @type {TresVector3}\n   * @memberof OrbitControlsProps\n   * @see https://threejs.org/docs/#examples/en/controls/OrbitControls.target\n   */\n  target?: TresVector3\n  /**\n   * Whether to enable damping (inertia)\n   *\n   * @default false\n   * @type {boolean}\n   * @memberof OrbitControlsProps\n   * @see https://threejs.org/docs/#examples/en/controls/OrbitControls.enableDamping\n   */\n  enableDamping?: boolean\n  /**\n   * The damping inertia used if `.enableDamping` is set to true\n   *\n   * @default 0.05\n   * @type {number}\n   * @memberof OrbitControlsProps\n   * @see https://threejs.org/docs/#examples/en/controls/OrbitControls.dampingFactor\n   */\n  dampingFactor?: number\n  /**\n   * Set to true to automatically rotate around the target.\n   *\n   * @default false\n   * @type {boolean}\n   * @memberof OrbitControlsProps\n   * @see https://threejs.org/docs/#examples/en/controls/OrbitControls.autoRotate\n   */\n  autoRotate?: boolean\n  /**\n   * How fast to rotate around the target if `.autoRotate` is true.\n   *\n   * @default 2\n   * @type {number}\n   * @memberof OrbitControlsProps\n   * @see https://threejs.org/docs/#examples/en/controls/OrbitControls.autoRotateSpeed\n   */\n  autoRotateSpeed?: number\n  /**\n   * Whether to enable panning.\n   *\n   * @default true\n   * @type {boolean}\n   * @memberof OrbitControlsProps\n   * @see https://threejs.org/docs/#examples/en/controls/OrbitControls.enablePan\n   */\n  enablePan?: boolean\n  /**\n   * How fast to pan the camera when the keyboard is used. Default is 7.0 pixels per keypress.\n   *\n   * @default 7.0\n   * @type {number}\n   * @memberof OrbitControlsProps\n   * @see https://threejs.org/docs/#examples/en/controls/OrbitControls.keyPanSpeed\n   */\n  keyPanSpeed?: number\n  /**\n   * This object contains references to the keycodes for controlling camera panning.\n   * Default is the 4 arrow keys.\n   *\n   * @default `{ LEFT: 'ArrowLeft', UP: 'ArrowUp', RIGHT: 'ArrowRight', BOTTOM: 'ArrowDown' }`\n   * @type Record<string, string>\n   * @memberof OrbitControlsProps\n   * @see https://threejs.org/docs/#examples/en/controls/OrbitControls.keys\n   */\n  keys?: Record<string, string>\n  /**\n   * How far you can orbit horizontally, upper limit.\n   * If set, the interval [ min, max ] must be a sub-interval of [ - 2 PI, 2 PI ],\n   * with ( max - min < 2 PI ). Default is Infinity.\n   *\n   * @default Infinity\n   * @type {number}\n   * @memberof OrbitControlsProps\n   * @see https://threejs.org/docs/index.html?q=orbi#examples/en/controls/OrbitControls.maxAzimuthAngle\n   */\n  maxAzimuthAngle?: number\n  /**\n   * How far you can orbit horizontally, lower limit.\n   * If set, the interval [ min, max ] must be a sub-interval of [ - 2 PI, 2 PI ],\n   * with ( max - min < 2 PI ).\n   * Default is - Infinity.\n   *\n   * @default -Infinity\n   * @type {number}\n   * @memberof OrbitControlsProps\n   * @see https://threejs.org/docs/index.html?q=orbi#examples/en/controls/OrbitControls.minAzimuthAngle\n   */\n  minAzimuthAngle?: number\n  /**\n   * How far you can orbit vertically, upper limit.\n   * Range is 0 to Math.PI radians, and default is Math.PI.\n   *\n   * @default Math.PI\n   * @type {number}\n   * @memberof OrbitControlsProps\n   * @see https://threejs.org/docs/index.html?q=orbi#examples/en/controls/OrbitControls.maxPolarAngle\n   */\n  maxPolarAngle?: number\n  /**\n   * How far you can orbit vertically, lower limit.\n   * Range is 0 to Math.PI radians, and default is 0.\n   *\n   * @default 0\n   * @type {number}\n   * @memberof OrbitControlsProps\n   * @see https://threejs.org/docs/index.html?q=orbi#examples/en/controls/OrbitControls.minPolarAngle\n   */\n  minPolarAngle?: number\n  /**\n   * The minimum distance of the camera to the target.\n   * Default is 0.\n   *\n   * @default 0\n   * @type {number}\n   * @memberof OrbitControlsProps\n   * @see https://threejs.org/docs/index.html?q=orbi#examples/en/controls/OrbitControls.minDistance\n   */\n  minDistance?: number\n  /**\n   * The maximum distance of the camera to the target.\n   * Default is Infinity.\n   *\n   * @default Infinity\n   * @type {number}\n   * @memberof OrbitControlsProps\n   * @see https://threejs.org/docs/index.html?q=orbi#examples/en/controls/OrbitControls.maxDistance\n   */\n  maxDistance?: number\n  /**\n   * The minimum field of view angle, in radians.\n   * Default is 0.\n   *\n   * @default 0\n   * @type {number}\n   * @memberof OrbitControlsProps\n   * @see https://threejs.org/docs/index.html?q=orbi#examples/en/controls/OrbitControls.minZoom\n   */\n  minZoom?: number\n  /**\n   * The maximum field of view angle, in radians.\n   * ( OrthographicCamera only ).\n   * Default is Infinity.\n   *\n   * @default Infinity\n   * @type {number}\n   * @memberof OrbitControlsProps\n   * @see https://threejs.org/docs/index.html?q=orbi#examples/en/controls/OrbitControls.maxZoom\n   */\n  maxZoom?: number\n  touches?: {\n    ONE?: number | undefined\n    TWO?: number | undefined\n  }\n  /**\n   * Whether to enable zooming.\n   *\n   * @default true\n   * @type {boolean}\n   * @memberof OrbitControlsProps\n   * @see https://threejs.org/docs/#examples/en/controls/OrbitControls.enableZoom\n   */\n  enableZoom?: boolean\n  /**\n   * How fast to zoom in and out. Default is 1.\n   *\n   * @default 1\n   * @type {number}\n   * @memberof OrbitControlsProps\n   * @see https://threejs.org/docs/#examples/en/controls/OrbitControls.zoomSpeed\n   */\n  zoomSpeed?: number\n  /**\n   * Whether to enable rotating.\n   *\n   * @default true\n   * @type {boolean}\n   * @memberof OrbitControlsProps\n   * @see https://threejs.org/docs/#examples/en/controls/OrbitControls.enableRotate\n   */\n  enableRotate?: boolean\n  /**\n   * How fast to rotate around the target. Default is 1.\n   *\n   * @default 1\n   * @type {number}\n   * @memberof OrbitControlsProps\n   * @see https://threejs.org/docs/#examples/en/controls/OrbitControls.rotateSpeed\n   */\n  rotateSpeed?: number\n  /**\n   * This object contains references to the mouse actions used by the controls.\n   * LEFT: Rotate around the target\n   * MIDDLE: Zoom the camera\n   * RIGHT: Pan the camera\n   *\n   * @default { LEFT: MOUSE.ROTATE, MIDDLE: MOUSE.DOLLY, RIGHT: MOUSE.PAN }\n   * @type {{ LEFT?: number, MIDDLE?: number, RIGHT?: number }}\n   * @memberof OrbitControlsProps\n   * @see https://threejs.org/docs/#examples/en/controls/OrbitControls.mouseButtons\n   */\n  mouseButtons?: {\n    LEFT?: number\n    MIDDLE?: number\n    RIGHT?: number\n  }\n}\n\nconst props = withDefaults(defineProps<OrbitControlsProps>(), {\n  makeDefault: false,\n  autoRotate: false,\n  autoRotateSpeed: 2,\n  enableDamping: true,\n  dampingFactor: 0.05,\n  enablePan: true,\n  keyPanSpeed: 7,\n  maxAzimuthAngle: Number.POSITIVE_INFINITY,\n  minAzimuthAngle: Number.NEGATIVE_INFINITY,\n  maxPolarAngle: Math.PI,\n  minPolarAngle: 0,\n  minDistance: 0,\n  maxDistance: Number.POSITIVE_INFINITY,\n  minZoom: 0,\n  maxZoom: Number.POSITIVE_INFINITY,\n  enableZoom: true,\n  zoomSpeed: 1,\n  enableRotate: true,\n  touches: () => ({ ONE: TOUCH.ROTATE, TWO: TOUCH.DOLLY_PAN }),\n  rotateSpeed: 1,\n  target: () => [0, 0, 0],\n  mouseButtons: () => ({ LEFT: MOUSE.ROTATE, MIDDLE: MOUSE.DOLLY, RIGHT: MOUSE.PAN }),\n})\n\nconst emit = defineEmits(['change', 'start', 'end'])\n\nconst {\n  makeDefault,\n  autoRotate,\n  autoRotateSpeed,\n  enableDamping,\n  dampingFactor,\n  enablePan,\n  keyPanSpeed,\n  maxAzimuthAngle,\n  minAzimuthAngle,\n  maxPolarAngle,\n  minPolarAngle,\n  minDistance,\n  maxDistance,\n  minZoom,\n  maxZoom,\n  enableZoom,\n  zoomSpeed,\n  enableRotate,\n  touches,\n  rotateSpeed,\n  target,\n  mouseButtons,\n} = toRefs(props)\n\nconst { camera: activeCamera, renderer, extend, controls, invalidate } = useTres()\n\nconst controlsRef = shallowRef<OrbitControls | null>(null)\n\nextend({ OrbitControls })\n\nwatch(controlsRef, (value) => {\n  addEventListeners()\n  if (value && makeDefault.value) {\n    controls.value = value\n  }\n  else {\n    controls.value = null\n  }\n})\n\nfunction addEventListeners() {\n  useEventListener(controlsRef.value as any, 'change', () => {\n    emit('change', controlsRef.value)\n    invalidate()\n  })\n  useEventListener(controlsRef.value as any, 'start', () => emit('start', controlsRef.value))\n  useEventListener(controlsRef.value as any, 'end', () => emit('end', controlsRef.value))\n}\n\nconst { onBeforeRender } = useLoop()\n\nonBeforeRender(() => {\n  if (controlsRef.value && (enableDamping.value || autoRotate.value)) {\n    controlsRef.value.update()\n\n    if (autoRotate.value) {\n      // TODO: comment this until invalidate is back in the loop callback on v5\n      // invalidate()\n    }\n  }\n})\n\nonUnmounted(() => {\n  if (controlsRef.value) {\n    controlsRef.value.dispose()\n  }\n})\n\ndefineExpose({ instance: controlsRef })\n</script>\n\n<template>\n  <TresOrbitControls\n    v-if=\"(camera || activeCamera) && (domElement || renderer.domElement)\"\n    ref=\"controlsRef\"\n    :key=\"(camera || activeCamera)?.uuid\"\n    :target=\"target\"\n    :auto-rotate=\"autoRotate\"\n    :auto-rotate-speed=\"autoRotateSpeed\"\n    :enable-damping=\"enableDamping\"\n    :damping-factor=\"dampingFactor\"\n    :enable-pan=\"enablePan\"\n    :key-pan-speed=\"keyPanSpeed\"\n    :keys=\"keys\"\n    :max-azimuth-angle=\"maxAzimuthAngle\"\n    :min-azimuth-angle=\"minAzimuthAngle\"\n    :max-polar-angle=\"maxPolarAngle\"\n    :min-polar-angle=\"minPolarAngle\"\n    :min-distance=\"minDistance\"\n    :max-distance=\"maxDistance\"\n    :min-zoom=\"minZoom\"\n    :max-zoom=\"maxZoom\"\n    :touches=\"touches\"\n    :enable-zoom=\"enableZoom\"\n    :zoom-speed=\"zoomSpeed\"\n    :enable-rotate=\"enableRotate\"\n    :rotate-speed=\"rotateSpeed\"\n    :mouse-buttons=\"mouseButtons\"\n    :args=\"[camera || activeCamera, domElement || renderer.domElement]\"\n  />\n</template>\n"
  },
  {
    "path": "src/core/controls/PointerLockControls.vue",
    "content": "<script lang=\"ts\" setup>\nimport { useTres } from '@tresjs/core'\nimport { useEventListener } from '@vueuse/core'\nimport { PointerLockControls } from 'three-stdlib'\nimport { onUnmounted, shallowRef, watch } from 'vue'\nimport type { Camera, EventDispatcher } from 'three'\n\n// Define the event types for PointerLockControls\ninterface PointerLockControlsEvents {\n  lock: () => void\n  unlock: () => void\n}\n\n// Extend the PointerLockControls type to include enabled property\ntype ExtendedPointerLockControls = PointerLockControls & EventDispatcher<PointerLockControlsEvents> & { enabled: boolean }\n\nexport interface PointerLockControlsProps {\n  /**\n   * Whether to make this the default controls.\n   *\n   * @default false\n   * @type {boolean}\n   * @memberof PointerLockControlsProps\n   * @see https://threejs.org/docs/index.html?q=pointe#examples/en/controls/PointerLockControls\n   */\n  makeDefault?: boolean\n  /**\n   * The camera to control.\n   *\n   * @default false\n   * @type {boolean}\n   * @memberof PointerLockControlsProps\n   * @see https://threejs.org/docs/index.html?q=pointe#examples/en/controls/PointerLockControls\n   */\n  camera?: Camera\n  /**\n   * The dom element to listen to.\n   *\n   * @type {HTMLElement}\n   * @memberof PointerLockControlsProps\n   * @see https://threejs.org/docs/index.html?q=pointe#examples/en/controls/PointerLockControls\n   */\n  domElement?: HTMLElement\n  /**\n   * The trigger id.\n   *\n   * @type {string}\n   * @memberof PointerLockControlsProps\n   * @see https://threejs.org/docs/index.html?q=pointe#examples/en/controls/PointerLockControls\n   */\n  selector?: string\n}\n\nconst props = withDefaults(defineProps<PointerLockControlsProps>(), {\n  makeDefault: false,\n})\n\nconst emit = defineEmits(['isLock', 'change'])\n\nconst { camera: activeCamera, renderer, extend, controls, invalidate } = useTres()\n\nwatch(props, () => {\n  invalidate()\n})\n\nconst controlsRef = shallowRef<ExtendedPointerLockControls | null>(null)\nlet triggerSelector: HTMLElement | undefined\n\nextend({ PointerLockControls })\n\nconst isLockEmitter = (event: boolean) => {\n  emit('isLock', event)\n}\n\nwatch(controlsRef, (value) => {\n  if (value && props.makeDefault) {\n    controls.value = value\n  }\n  else {\n    controls.value = null\n  }\n  const selector = document.getElementById(props.selector || '')\n  triggerSelector = selector || renderer.domElement\n\n  useEventListener(triggerSelector, 'click', () => {\n    if (controlsRef.value) {\n      controlsRef.value.lock()\n      controlsRef.value.addEventListener('lock', () => isLockEmitter(true))\n      controlsRef.value.addEventListener('unlock', () => isLockEmitter(false))\n      invalidate()\n    }\n  })\n})\n\nonUnmounted(() => {\n  const controls = controlsRef.value\n  if (controls) {\n    controls.removeEventListener('lock', () => isLockEmitter(true))\n    controls.removeEventListener('unlock', () => isLockEmitter(false))\n    controls.dispose()\n  }\n})\n\ndefineExpose({\n  instance: controls,\n})\n</script>\n\n<template>\n  <TresPointerLockControls\n    v-if=\"(camera || activeCamera) && (domElement || renderer.domElement)\"\n    ref=\"controlsRef\"\n    :args=\"[camera || activeCamera, domElement || renderer.domElement]\"\n  />\n</template>\n"
  },
  {
    "path": "src/core/controls/ScrollControls.vue",
    "content": "<script setup lang=\"ts\">\nimport { logWarning, useLoop, useTresContext } from '@tresjs/core'\nimport { useScroll, useWindowScroll, useWindowSize } from '@vueuse/core'\nimport { ref, shallowRef, watch } from 'vue'\n\nexport interface ScrollControlsProps {\n  /**\n   * The scroll size.\n   *\n   * @type {number}\n   * @default 4\n   * @memberof ScrollControlsProps\n   */\n  pages?: number\n  /**\n   * The distance to move the camera.\n   *\n   * @type {number}\n   * @default 4\n   * @memberof ScrollControlsProps\n   */\n  distance?: number\n  /**\n   * The smooth factor of the scrolling.\n   *\n   * @type {number}\n   * @default 0.1\n   * @memberof ScrollControlsProps\n   */\n  smoothScroll?: number\n  /**\n   * Whether the scroll is horizontal or vertical.\n   *\n   * @type {boolean}\n   * @default false\n   * @memberof ScrollControlsProps\n   */\n  horizontal?: boolean\n  /**\n   * Whether to use the HTML scroll.\n   *\n   * @type {boolean}\n   * @default false\n   * @memberof ScrollControlsProps\n   */\n  htmlScroll?: boolean\n}\n\nconst props = withDefaults(\n  defineProps<{\n    pages?: number\n    distance?: number\n    smoothScroll?: number\n    horizontal?: boolean\n    htmlScroll?: boolean\n  }>(),\n  {\n    pages: 4,\n    distance: 4,\n    smoothScroll: 0.1,\n    horizontal: false,\n    htmlScroll: false,\n  },\n)\n\nconst emit = defineEmits(['update:modelValue'])\n\nif (props.smoothScroll < 0) { logWarning('SmoothControl must be greater than zero') }\nif (props.pages < 0) { logWarning('Pages must be greater than zero') }\n\nconst { camera, controls, renderer } = useTresContext()\n\nwatch(props, () => {\n  renderer.invalidate()\n})\nconst wrapperRef = shallowRef()\nconst scrollContainer = document.createElement('div')\n\nconst { y: windowY } = useWindowScroll()\nconst { x: containerX, y: containerY, isScrolling } = useScroll(scrollContainer)\n\nconst { height, width } = useWindowSize()\n\nlet initCameraPos = 0\nconst initialized = ref(false)\n\nconst progress = ref(0)\nconst progressScroll = ref(0)\nconst scrollNodeY = ref(0)\nconst direction = props.horizontal ? 'x' : 'y'\n\nconst unWatch = watch(\n  camera.activeCamera,\n  (value) => {\n    if (initialized.value) {\n      unWatch()\n      return\n    }\n    initCameraPos = props.horizontal ? value?.position.x || 0 : value?.position.y || 0\n    initialized.value = true\n  },\n  {\n    immediate: true,\n  },\n)\n\nwatch(\n  isScrolling,\n  (value) => {\n    if (controls.value) { controls.value.enabled = !value }\n  },\n  {\n    immediate: true,\n  },\n)\n\nwatch(windowY, (value) => {\n  if (!isScrolling.value && !props.htmlScroll) { return }\n  progressScroll.value = (value / height.value / (scrollNodeY.value / height.value - 1))\n  progress.value = -1 * progressScroll.value\n  emit('update:modelValue', progressScroll.value)\n})\nwatch(containerY, (value) => {\n  progressScroll.value = (value / height.value / (scrollNodeY.value / height.value))\n  progress.value = -1 * progressScroll.value\n  emit('update:modelValue', progressScroll.value)\n})\nwatch(containerX, (value) => {\n  progressScroll.value = (value / width.value / (scrollNodeY.value / width.value - 1))\n  progress.value = +progressScroll.value\n  emit('update:modelValue', progressScroll.value)\n})\n\nwatch(\n  renderer.instance,\n  (value) => {\n    const canvas = value?.domElement\n    if (props.htmlScroll && value?.domElement) {\n      // use window scroll only Y axis\n      if (canvas?.style.width && canvas?.style.position && canvas?.style.top && canvas?.style.left) {\n        canvas.style.width = '100%'\n        canvas.style.position = 'fixed'\n        canvas.style.zIndex = ' -99999'\n        canvas.style.top = '0'\n        canvas.style.left = '0'\n      }\n      scrollNodeY.value = document.body.scrollHeight\n    }\n    else {\n      const fixed = document.createElement('div')\n      const fill = document.createElement('div')\n\n      scrollContainer.style[props.horizontal ? 'overflowX' : 'overflowY'] = 'auto'\n      scrollContainer.style[props.horizontal ? 'overflowY' : 'overflowX'] = 'hidden'\n      scrollContainer.style.position = 'absolute'\n      scrollContainer.style.width = '100%'\n      scrollContainer.style.height = ' 100%'\n      scrollContainer.style.top = '0'\n      scrollContainer.style.left = '0'\n      scrollContainer.classList.add('scrollContainer')\n\n      fixed.style.position = 'sticky'\n      fixed.style.top = '0px'\n      fixed.style.left = '0px'\n      fixed.style.width = '100%'\n      fixed.style.height = '100%'\n      fixed.style.overflow = 'hidden'\n      scrollContainer.appendChild(fixed)\n\n      fill.style.height = props.horizontal ? '100%' : `${height.value * props.pages}px`\n      fill.style.width = props.horizontal ? `${width.value * props.pages}px` : '100vw'\n      fill.style.pointerEvents = 'none'\n      canvas.style.position = 'fixed'\n      canvas.style.zIndex = '0'\n      if (canvas?.style.width) {\n        canvas.style.width = '100%'\n      }\n      scrollContainer.appendChild(fill)\n      if (value?.domElement.parentNode) {\n        (value.domElement.parentNode as HTMLElement).style.position = 'relative'\n      }\n      value?.domElement?.parentNode?.appendChild(scrollContainer)\n      scrollNodeY.value = props.horizontal ? width.value * props.pages : height.value * props.pages\n    }\n  },\n  {\n    immediate: true,\n  },\n)\n\nconst { onBeforeRender } = useLoop()\n\nonBeforeRender(() => {\n  if (camera.activeCamera.value?.position) {\n    const delta\n      = (progress.value * props.distance - camera.activeCamera.value.position[direction] + initCameraPos) * props.smoothScroll\n\n    camera.activeCamera.value.position[direction] += delta\n    if (wrapperRef.value.children.length > 0) {\n      wrapperRef.value.position[direction] += delta\n    }\n\n    // TODO: comment this until invalidate is back in the loop callback on v5\n    // invalidate()\n  }\n})\n\ndefineExpose({\n  instance: wrapperRef,\n})\n</script>\n\n<template>\n  <TresGroup ref=\"wrapperRef\">\n    <slot></slot>\n  </TresGroup>\n</template>\n"
  },
  {
    "path": "src/core/controls/TransformControls.vue",
    "content": "<script setup lang=\"ts\">\nimport { useTres } from '@tresjs/core'\nimport { useEventListener } from '@vueuse/core'\n\nimport { TransformControls } from 'three-stdlib'\nimport { onUnmounted, shallowRef, toRefs, watch } from 'vue'\nimport type { Camera, Event, Object3D } from 'three'\n\nexport interface TransformControlsProps {\n  object: Object3D\n  camera?: Camera\n  mode?: string\n  enabled?: boolean\n  axis?: 'X' | 'Y' | 'Z' | 'XY' | 'YZ' | 'XZ' | 'XYZ'\n  translationSnap?: number\n  rotationSnap?: number\n  scaleSnap?: number\n  space?: 'local' | 'world'\n  size?: number\n  showX?: boolean\n  showY?: boolean\n  showZ?: boolean\n}\n\nconst props = withDefaults(defineProps<TransformControlsProps>(), {\n  mode: 'translate',\n  enabled: true,\n  axis: 'XYZ',\n  space: 'world',\n  size: 1,\n  showX: true,\n  showY: true,\n  showZ: true,\n})\n\nconst emit = defineEmits(['dragging', 'change', 'mouseDown', 'mouseUp', 'objectChange'])\n\nconst { object, mode, enabled, axis, translationSnap, rotationSnap, scaleSnap, space, size, showX, showY, showZ }\n  = toRefs(props)\n\nconst controlsRef = shallowRef<TransformControls | null>(null)\n\nconst { controls, camera: activeCamera, renderer, extend, invalidate } = useTres()\n\nwatch([object, mode, enabled, axis, translationSnap, rotationSnap, scaleSnap, space, size, showX, showY, showZ], () => {\n  invalidate()\n})\n\nextend({ TransformControls })\n\nconst onChange = () => {\n  invalidate()\n  emit('change')\n}\n\ninterface DraggingEvent extends Event {\n  value: boolean\n}\n\nconst onDragingChange = (e: DraggingEvent) => {\n  if (controls.value) { controls.value.enabled = !(e).value }\n  invalidate()\n  emit('dragging', e.value)\n}\n\nconst onMouseDown = () => {\n  invalidate()\n  emit('mouseDown')\n}\n\nconst onMouseUp = () => {\n  invalidate()\n  emit('mouseUp')\n}\n\nconst onObjectChange = () => {\n  invalidate()\n  emit('objectChange')\n}\n\nfunction addEventListeners() {\n  useEventListener(controlsRef.value as any, 'change', onChange)\n  useEventListener(controlsRef.value as any, 'dragging-changed', onDragingChange)\n  useEventListener(controlsRef.value as any, 'mouseDown', onMouseDown)\n  useEventListener(controlsRef.value as any, 'mouseUp', onMouseUp)\n  useEventListener(controlsRef.value as any, 'objectChange', onObjectChange)\n}\n\nwatch(controlsRef, (value) => {\n  if (value) {\n    addEventListeners()\n  }\n})\n\nonUnmounted(() => {\n  if (controlsRef.value) {\n    controlsRef.value.dispose()\n  }\n})\n\ndefineExpose({\n  instance: controlsRef,\n})\n</script>\n\n<template>\n  <TresTransformControls\n    v-if=\"(camera || activeCamera) && renderer.domElement\"\n    ref=\"controlsRef\"\n    :key=\"(camera || activeCamera)?.uuid\"\n    :object=\"object\"\n    :args=\"[camera || activeCamera, renderer.domElement]\"\n    :mode=\"mode\"\n    :enabled=\"enabled\"\n    :axis=\"axis\"\n    :translation-snap=\"translationSnap\"\n    :rotation-snap=\"rotationSnap\"\n    :scale-snap=\"scaleSnap\"\n    :space=\"space\"\n    :size=\"size\"\n    :show-x=\"showX\"\n    :show-y=\"showY\"\n    :show-z=\"showZ\"\n    :visible=\"true\"\n  />\n</template>\n"
  },
  {
    "path": "src/core/controls/index.ts",
    "content": "import CameraControls, { BaseCameraControls } from './CameraControls.vue'\nimport Helper from './Helper/component.vue'\nimport KeyboardControls from './KeyboardControls.vue'\nimport MapControls from './MapControls.vue'\nimport OrbitControls from './OrbitControls.vue'\nimport PointerLockControls from './PointerLockControls.vue'\nimport ScrollControls from './ScrollControls.vue'\nimport TransformControls from './TransformControls.vue'\n\nexport {\n  BaseCameraControls,\n  CameraControls,\n  Helper,\n  KeyboardControls,\n  MapControls,\n  OrbitControls,\n  PointerLockControls,\n  ScrollControls,\n  TransformControls,\n}\n"
  },
  {
    "path": "src/core/index.ts",
    "content": "export * from './abstractions'\nexport * from './controls'\nexport * from './loaders'\nexport * from './materials'\nexport * from './misc'\nexport * from './shapes'\nexport * from './staging'\n"
  },
  {
    "path": "src/core/loaders/index.ts",
    "content": "import UseSVG from './useSVG/component.vue'\nimport FBXModel from './useFBX/component.vue'\nimport GLTFModel from './useGLTF/component.vue'\nimport UseTexture from './useTexture/component.vue'\nimport { useProgress } from './useProgress'\nimport { useVideoTexture } from './useVideoTexture'\n\nexport * from './useFBX'\nexport * from './useGLTF'\nexport * from './useSVG'\nexport * from './useTexture'\nexport * from './useTextures'\nexport { FBXModel, GLTFModel, useProgress, UseSVG, UseTexture, useVideoTexture }\n"
  },
  {
    "path": "src/core/loaders/useFBX/component.vue",
    "content": "<script setup lang=\"ts\">\nimport { watchEffect } from 'vue'\nimport { Mesh } from 'three'\nimport type { Group } from 'three'\nimport { useFBX } from '.'\n\nconst props = withDefaults(defineProps<FBXModelProps>(), {\n  castShadow: false,\n  receiveShadow: false,\n})\n\n// Use the new reactive useFBX composable with reactive path\nconst { state: model } = useFBX(props.path as string)\n\ndefineExpose({\n  instance: model,\n})\n\n// Apply shadow settings when the model loads or shadow props change\nwatchEffect(() => {\n  if (model.value && (props.castShadow || props.receiveShadow)) {\n    ;(model.value as Group).traverse((child) => {\n      if (child instanceof Mesh) {\n        child.castShadow = props.castShadow\n        child.receiveShadow = props.receiveShadow\n      }\n    })\n  }\n})\n</script>\n\n<script lang=\"ts\">\nexport interface FBXModelProps {\n  /**\n   * Path to the FBX file.\n   *\n   * @type {string}\n   * @memberof FBXModelProps\n   * @required\n   */\n  path: string\n  /**\n   *\n   * Whether to use cast-shadow to the model.\n   *\n   * @type {boolean}\n   * @default false\n   * @memberof FBXModelProps\n   *\n   */\n  castShadow?: boolean\n  /**\n   *\n   * Whether to use receive-shadow to the model.\n   *\n   * @type {boolean}\n   * @default false\n   * @memberof FBXModelProps\n   *\n   */\n  receiveShadow?: boolean\n}\n</script>\n\n<template>\n  <primitive\n    :object=\"model\"\n    v-bind=\"$attrs\"\n  />\n</template>\n"
  },
  {
    "path": "src/core/loaders/useFBX/index.ts",
    "content": "import type { TresObject } from '@tresjs/core'\nimport { buildGraph, useLoader } from '@tresjs/core'\n\nimport { computed, type ComputedRef, type MaybeRef, type Ref, watch } from 'vue'\nimport type { Group } from 'three'\n\nimport { FBXLoader } from 'three-stdlib'\n\nexport interface UseFBXOptions {\n  /**\n   * A traverse function applied to the scene upon loading the model.\n   * @type {Function}\n   */\n  traverse?: (child: TresObject) => void\n}\n\n/**\n * Vue composable for loading FBX models in TresJS\n *\n * @remarks\n * This composable uses Three.js FBXLoader under the hood to load FBX 3D models.\n * The loaded model is automatically parsed and made available as a reactive state.\n *\n * @example\n * ```ts\n * const { state: model } = useFBX('/path/to/model.fbx')\n * ```\n *\n * @param {MaybeRef<string>} path - Path to the FBX model file\n * @returns {{ state: Group, isLoading: boolean, execute: () => Promise<void>, nodes: object, materials: object }} Object containing the model state, loading state, reload function, and parsed nodes/materials\n */\nexport function useFBX(path: MaybeRef<string>, options?: UseFBXOptions): {\n  state: Ref<Group | null>\n  isLoading: Ref<boolean>\n  execute: (delay?: number, ...args: any[]) => Promise<Group>\n  nodes: ComputedRef<Record<string, any>>\n  materials: ComputedRef<Record<string, any>>\n} {\n  const result = useLoader(FBXLoader, path)\n  if (options?.traverse) {\n    watch(result.state, (state) => {\n      state.traverse(child => options.traverse?.(child as TresObject))\n    })\n  }\n\n  // Extract nodes from the loaded FBX model for easy access\n  const nodes = computed(() => {\n    return result.state.value ? buildGraph(result.state.value as unknown as TresObject).nodes : {}\n  })\n\n  // Extract materials from the loaded FBX model for easy access\n  const materials = computed(() => {\n    return result.state.value ? buildGraph(result.state.value as unknown as TresObject).materials : {}\n  })\n\n  return {\n    ...result,\n    nodes,\n    materials,\n  }\n}\n"
  },
  {
    "path": "src/core/loaders/useGLTF/component.vue",
    "content": "<script setup lang=\"ts\">\nimport { watchEffect } from 'vue'\nimport { Mesh } from 'three'\nimport { useGLTF } from '.'\n\nconst props = withDefaults(\n  defineProps<GLTFModelProps>(),\n  {\n    draco: false,\n    castShadow: false,\n    receiveShadow: false,\n    decoderPath: 'https://www.gstatic.com/draco/versioned/decoders/1.4.1/',\n  },\n)\n\nconst { state, isLoading } = useGLTF(props.path as string, {\n  draco: props.draco,\n  decoderPath: props.decoderPath,\n})\n\ndefineExpose({\n  instance: state,\n})\n\n// Apply shadow settings when the model loads or shadow props change\nwatchEffect(() => {\n  if (state.value?.scene && (props.castShadow || props.receiveShadow)) {\n    state.value.scene.traverse((child) => {\n      if (child instanceof Mesh) {\n        child.castShadow = props.castShadow\n        child.receiveShadow = props.receiveShadow\n      }\n    })\n  }\n})\n</script>\n\n<script lang=\"ts\">\nexport interface GLTFModelProps {\n  /**\n   *\n   * The path to the GLTF file.\n   *\n   * @type {string}\n   * @required\n   * @memberof GLTFModelProps\n   *\n   */\n  path: string\n  /**\n   *\n   * Whether to use Draco compression.\n   *\n   * @type {boolean}\n   * @default false\n   * @memberof GLTFModelProps\n   *\n   */\n  draco?: boolean\n  /**\n   *\n   * Whether to use cast-shadow to the model.\n   *\n   * @type {boolean}\n   * @default false\n   * @memberof GLTFModelProps\n   *\n   */\n  castShadow?: boolean\n  /**\n   *\n   * Whether to use receive-shadow to the model.\n   *\n   * @type {boolean}\n   * @default false\n   * @memberof GLTFModelProps\n   *\n   */\n  receiveShadow?: boolean\n  /**\n   *\n   * The path to the Draco decoder.\n   *\n   * @type {string}\n   * @default 'https://www.gstatic.com/draco/versioned/decoders/1.4.1/'\n   * @memberof GLTFModelProps\n   *\n   */\n  decoderPath?: string\n}\n</script>\n\n<template>\n  <primitive\n    v-if=\"!isLoading && state?.scene\"\n    :object=\"state?.scene\"\n    v-bind=\"$attrs\"\n  />\n</template>\n"
  },
  {
    "path": "src/core/loaders/useGLTF/index.ts",
    "content": "import type { TresLoader, TresLoaderOptions, TresObject } from '@tresjs/core'\nimport { buildGraph, useLoader } from '@tresjs/core'\n\nimport { computed, type ComputedRef, type MaybeRef, type Ref, watch } from 'vue'\n\nimport type { GLTF } from 'three-stdlib'\nimport { DRACOLoader, GLTFLoader } from 'three-stdlib'\n\nexport interface UseGLTFOptions {\n  /**\n   * Whether to use DRACO compression for loading the model\n   * @type {boolean}\n   */\n  draco?: boolean\n  /**\n   * Path to the DRACO decoder. Defaults to https://www.gstatic.com/draco/versioned/decoders/1.5.6/\n   * @type {string}\n   */\n  decoderPath?: string\n  /**\n   * A traverse function applied to the scene upon loading the model.\n   * @type {Function}\n   */\n  traverse?: (child: TresObject) => void\n}\n\n/**\n * Vue composable for loading GLTF models in TresJS\n *\n * @remarks\n * This composable uses Three.js GLTFLoader under the hood and supports DRACO compression.\n * When DRACO compression is enabled, it will use the specified decoder path or fallback to Google's CDN.\n *\n * @example\n * ```ts\n * const { state: model } = useGLTF('/path/to/model.glb', { draco: true })\n * ```\n *\n * @param {MaybeRef<string>} path - Path to the GLTF model file\n * @param {UseGLTFOptions} options - Options for loading the model\n * @returns {{ state: GLTF, isLoading: boolean, execute: () => Promise<void> }} Object containing the model state, loading state and reload function\n */\nexport function useGLTF(path: MaybeRef<string>, options?: UseGLTFOptions): {\n  state: Ref<GLTF | null>\n  isLoading: Ref<boolean>\n  execute: (delay?: number, ...args: any[]) => Promise<GLTF>\n  nodes: ComputedRef<Record<string, any>>\n  materials: ComputedRef<Record<string, any>>\n} {\n  const useLoaderOptions: TresLoaderOptions<GLTF, true> = {\n\n  }\n  if (options?.draco) {\n    const dracoLoader = new DRACOLoader()\n    // Set the path to the Draco decoder (you might want to use a CDN or local path)\n    dracoLoader.setDecoderPath(options.decoderPath || 'https://www.gstatic.com/draco/versioned/decoders/1.5.6/')\n    useLoaderOptions.extensions = (loader: TresLoader<GLTF>) => {\n      if (loader instanceof GLTFLoader) {\n        loader.setDRACOLoader(dracoLoader)\n      }\n    }\n  }\n\n  const result = useLoader(GLTFLoader, path, useLoaderOptions)\n  if (options?.traverse) {\n    watch(result.state, (state) => {\n      state.scene.traverse(child => options.traverse?.(child as TresObject))\n    })\n  }\n\n  const nodes = computed(() => {\n    return result.state.value?.scene ? buildGraph(result.state.value?.scene as unknown as TresObject).nodes : {}\n  })\n\n  const materials = computed(() => {\n    return result.state.value?.scene ? buildGraph(result.state.value?.scene as unknown as TresObject).materials : {}\n  })\n\n  return {\n    ...result,\n    nodes,\n    materials,\n  }\n}\n"
  },
  {
    "path": "src/core/loaders/useProgress.ts",
    "content": "import { logError } from '@tresjs/core'\nimport { DefaultLoadingManager } from 'three'\nimport { ref } from 'vue'\nimport type { Ref } from 'vue'\n\nlet saveLastTotalLoaded = 0\n\nexport function useProgress(): Promise<{\n  hasFinishLoading: Ref<boolean>\n  progress: Ref<number>\n  items: Ref<string[]>\n}> {\n  const hasFinishLoading = ref(false)\n  const progress = ref(0)\n  const items: Ref<string[]> = ref([])\n\n  return new Promise((resolve) => {\n    DefaultLoadingManager.onStart = () => {\n      hasFinishLoading.value = false\n    }\n\n    DefaultLoadingManager.onLoad = () => {\n      hasFinishLoading.value = true\n    }\n\n    DefaultLoadingManager.onProgress = (item, loaded, total) => {\n      if (loaded === total) {\n        saveLastTotalLoaded = total\n        hasFinishLoading.value = true\n        items.value.push(item)\n      }\n      progress.value = Math.round(((loaded - saveLastTotalLoaded) / (total - saveLastTotalLoaded)) * 100 || 100)\n    }\n\n    DefaultLoadingManager.onError = (error) => {\n      logError('Error loading assets', new Error(error))\n      hasFinishLoading.value = true\n    }\n\n    resolve({\n      items,\n      hasFinishLoading,\n      progress,\n    })\n  })\n}\n"
  },
  {
    "path": "src/core/loaders/useSVG/component.vue",
    "content": "<script setup lang=\"ts\">\nimport { onUnmounted } from 'vue'\nimport type { TresOptions } from '@tresjs/core'\nimport type { MeshBasicMaterialParameters } from 'three'\nimport { useSVG } from '.'\n\nconst props = withDefaults(defineProps<SVGProps>(), {\n  skipStrokes: false,\n  skipFills: false,\n  depth: 'renderOrder',\n})\n\ninterface SVGProps {\n  /**\n   *\n   * The SVG data or path to an SVG file\n   *\n   * @type {string}\n   * @required\n   * @memberof SVGProps\n   *\n   */\n  src: string\n  /**\n   *\n   * Whether to draw strokes\n   *\n   * @type {boolean}\n   * @default false\n   * @memberof SVGProps\n   *\n   */\n  skipStrokes?: boolean\n  /**\n   *\n   * Whether to draw fills\n   *\n   * @type {boolean}\n   * @default false\n   * @memberof SVGProps\n   *\n   */\n  skipFills?: boolean\n  /**\n   *\n   * Fill material properties\n   *\n   * @type {MeshBasicMaterialParameters}\n   * @default undefined\n   * @memberof SVGProps\n   *\n   */\n  fillMaterial?: MeshBasicMaterialParameters\n  /**\n   *\n   * Stroke material properties\n   *\n   * @type {MeshBasicMaterialParameters}\n   * @default undefined\n   * @memberof SVGProps\n   *\n   */\n  strokeMaterial?: MeshBasicMaterialParameters\n  /**\n   *\n   * Fill Mesh properties\n   *\n   * @type {TresOptions}\n   * @default undefined\n   * @memberof SVGProps\n   *\n   */\n  fillMeshProps?: TresOptions\n  /**\n   *\n   * Stroke Mesh properties\n   *\n   * @type {TresOptions}\n   * @default undefined\n   * @memberof SVGProps\n   *\n   */\n  strokeMeshProps?: TresOptions\n  /**\n   *\n   * Depth type\n   * How should the resulting meshes and materials be rendered?\n   * 'renderOrder' disables `depthWrite` and sets the `renderOrder` of each layer.\n   * 'flat' disables `depthWrite` on materials.\n   * 'offsetZ' enables `depthWrite` and inserts a small distance between each layer on the z-axis to avoid z-fighting.\n   * number is treated the same as 'offsetZ'; the number is used as the distance between layers\n   *\n   * depthWrite documentation: https://threejs.org/docs/#api/en/materials/Material.depthWrite\n   * renderOrder documentation: https://threejs.org/docs/?q=mesh#api/en/core/Object3D.renderOrder\n   *\n   * @type { 'renderOrder' | 'flat' | 'offsetZ' | number }\n   * @default 'renderOrder'\n   * @memberof SVGProps\n   *\n   */\n  depth?: 'renderOrder' | 'flat' | 'offsetZ' | number\n}\n\n// Use the useSVG composable with all the processing logic\nconst { state, isLoading, layers, dispose } = useSVG(props.src, {\n  skipStrokes: props.skipStrokes,\n  skipFills: props.skipFills,\n  fillMaterial: props.fillMaterial,\n  strokeMaterial: props.strokeMaterial,\n  depth: props.depth,\n})\n\ndefineExpose({\n  instance: state,\n  layers,\n})\n\n// Clean up geometries when component unmounts\nonUnmounted(() => {\n  dispose()\n})\n</script>\n\n<template>\n  <TresGroup v-if=\"!isLoading\">\n    <TresMesh\n      v-for=\"({ geometry, material, isStroke }, i) of layers\"\n      :key=\"`${i}`\"\n      v-bind=\"isStroke ? props.strokeMeshProps : props.fillMeshProps\"\n      :geometry=\"geometry\"\n      :render-order=\"props.depth === 'renderOrder' ? i : 0\"\n    >\n      <TresMeshBasicMaterial v-bind=\"material\" />\n    </TresMesh>\n  </TresGroup>\n</template>\n"
  },
  {
    "path": "src/core/loaders/useSVG/index.ts",
    "content": "import type { TresLoaderOptions } from '@tresjs/core'\nimport { useLoader } from '@tresjs/core'\nimport { computed, type ComputedRef, type MaybeRef, type Ref } from 'vue'\nimport { DoubleSide, ShapeGeometry, Vector2 } from 'three'\nimport { SVGLoader } from 'three-stdlib'\nimport type { BufferGeometry, MeshBasicMaterialParameters } from 'three'\nimport type { SVGResult } from 'three-stdlib'\n\nexport interface UseSVGOptions {\n  /**\n   * Whether to skip rendering strokes\n   * @type {boolean}\n   * @default false\n   */\n  skipStrokes?: boolean\n  /**\n   * Whether to skip rendering fills\n   * @type {boolean}\n   * @default false\n   */\n  skipFills?: boolean\n  /**\n   * Fill material properties\n   * @type {MeshBasicMaterialParameters}\n   */\n  fillMaterial?: MeshBasicMaterialParameters\n  /**\n   * Stroke material properties\n   * @type {MeshBasicMaterialParameters}\n   */\n  strokeMaterial?: MeshBasicMaterialParameters\n  /**\n   * Depth type - how should the resulting meshes be rendered?\n   * 'renderOrder' disables depthWrite and sets renderOrder of each layer\n   * 'flat' disables depthWrite on materials\n   * 'offsetZ' enables depthWrite and inserts small distance between layers\n   * number is treated same as 'offsetZ' using the number as distance\n   * @type {'renderOrder' | 'flat' | 'offsetZ' | number}\n   * @default 'renderOrder'\n   */\n  depth?: 'renderOrder' | 'flat' | 'offsetZ' | number\n}\n\nexport interface SVGLayer {\n  geometry: BufferGeometry\n  material: MeshBasicMaterialParameters\n  isStroke: boolean\n}\n\n/**\n * Vue composable for loading SVG files in TresJS\n *\n * @remarks\n * This composable uses Three.js SVGLoader under the hood to load and process SVG files\n * into geometries and materials that can be rendered in a 3D scene.\n *\n * @example\n * ```ts\n * const { state: svg, layers } = useSVG('/path/to/file.svg', { skipStrokes: false })\n * ```\n *\n * @param {MaybeRef<string>} path - Path to the SVG file or SVG data string\n * @param {UseSVGOptions} options - Options for processing the SVG\n * @returns Object containing the SVG state, loading state, processed layers and disposal function\n */\nexport function useSVG(path: MaybeRef<string>, options: UseSVGOptions = {}): {\n  state: Ref<SVGResult | null>\n  isLoading: Ref<boolean>\n  execute: (delay?: number, ...args: any[]) => Promise<SVGResult>\n  layers: ComputedRef<SVGLayer[]>\n  dispose: () => void\n} {\n  const {\n    skipStrokes = false,\n    skipFills = false,\n    fillMaterial = {},\n    strokeMaterial = {},\n    depth = 'renderOrder',\n  } = options\n\n  // Convert SVG data to data URL if needed\n  const processedPath = computed(() => {\n    const pathValue = typeof path === 'string' ? path : path.value\n    return !pathValue.startsWith('<svg')\n      ? pathValue\n      : encodeURI(`data:image/svg+xml;utf8,${pathValue}`)\n  })\n\n  const useLoaderOptions: TresLoaderOptions<SVGResult, true> = {}\n\n  const result = useLoader(SVGLoader, processedPath, useLoaderOptions)\n\n  /**\n   * Process SVG paths into renderable layers\n   */\n  const layers = computed(() => {\n    if (!result.state.value?.paths) { return [] }\n\n    const _layers: SVGLayer[] = []\n    const paths = result.state.value.paths\n\n    // Determine depth settings\n    const [depthWrite, offsetZ] = (() => {\n      const DEPTH_WRITE = { flat: false, renderOrder: false, offsetZ: true }\n      const OFFSET_Z = { flat: 0, renderOrder: 0, offsetZ: 0.025 }\n      return typeof depth === 'number' ? [true, depth] : [DEPTH_WRITE[depth], OFFSET_Z[depth]]\n    })()\n\n    let layerIndex = 0\n\n    for (const path of paths) {\n      const style = path.userData?.style ?? {}\n\n      // Process fills\n      if (!skipFills && style.fill !== undefined && style.fill !== 'none') {\n        const fillMat = {\n          color: style.fill,\n          opacity: style.fillOpacity,\n          transparent: true,\n          side: DoubleSide,\n          depthWrite,\n          ...fillMaterial,\n        }\n\n        for (const shape of SVGLoader.createShapes(path)) {\n          const geometry = new ShapeGeometry(shape)\n          geometry.scale(1, -1, 1) // Flip Y-axis for correct orientation\n\n          if (offsetZ) {\n            geometry.translate(0, 0, layerIndex * offsetZ)\n          }\n\n          _layers.push({\n            geometry,\n            material: fillMat,\n            isStroke: false,\n          })\n          layerIndex++\n        }\n      }\n\n      // Process strokes\n      if (!skipStrokes && style.stroke !== undefined && style.stroke !== 'none') {\n        const strokeMat = {\n          color: style.stroke,\n          opacity: style.strokeOpacity,\n          transparent: true,\n          side: DoubleSide,\n          depthWrite,\n          ...strokeMaterial,\n        }\n\n        for (const subPath of path.subPaths) {\n          const points = subPath.getPoints().map(v2 => new Vector2(v2.x, -v2.y))\n          const geometry = SVGLoader.pointsToStroke(points, style)\n\n          if (offsetZ) {\n            geometry.translate(0, 0, layerIndex * offsetZ)\n          }\n\n          _layers.push({\n            geometry,\n            material: strokeMat,\n            isStroke: true,\n          })\n          layerIndex++\n        }\n      }\n    }\n\n    return _layers\n  })\n\n  /**\n   * Dispose of all geometries to free memory\n   */\n  const dispose = () => {\n    layers.value.forEach(layer => layer.geometry.dispose())\n  }\n\n  return {\n    ...result,\n    layers,\n    dispose,\n  }\n}\n"
  },
  {
    "path": "src/core/loaders/useTexture/component.vue",
    "content": "<script setup lang=\"ts\">\nimport type { LoadingManager, Texture } from 'three'\nimport { useTexture } from '.'\nimport { whenever } from '@vueuse/core'\n\nconst props = defineProps<{\n  /**\n   * The path to the texture file.\n   *\n   * @type {string}\n   * @required\n   * @memberof TextureProps\n   */\n  path: string\n  /**\n   * Optional THREE.js LoadingManager\n   */\n  manager?: LoadingManager\n}>()\n\nconst emit = defineEmits<{\n  loaded: [result: Texture]\n  error: [error: unknown]\n}>()\n// Use the useTexture composable to load the texture\nconst { state: texture, isLoading, error } = useTexture(props.path)\n\nwhenever(error, (err) => {\n  if (err) { emit('error', err) }\n})\n\nwhenever(texture, (value) => {\n  if (value) { emit('loaded', value) }\n})\n</script>\n\n<template>\n  <slot\n    :state=\"texture\"\n    :is-loading=\"isLoading\"\n    :error=\"error\"\n  ></slot>\n</template>\n"
  },
  {
    "path": "src/core/loaders/useTexture/index.ts",
    "content": "import { useLoader } from '@tresjs/core'\nimport { Texture, TextureLoader } from 'three'\nimport type { MaybeRef } from 'vue'\n\nexport function useTexture(path: MaybeRef<string>) {\n  const result = useLoader(TextureLoader, path, {\n    initialValue: new Texture(),\n  })\n\n  return result\n}\n"
  },
  {
    "path": "src/core/loaders/useTextures/index.ts",
    "content": "import { useLoader } from '@tresjs/core'\nimport { Texture, TextureLoader } from 'three'\nimport { computed, ref, unref } from 'vue'\nimport type { MaybeRef } from 'vue'\n\n/**\n * Composable that loads multiple textures at once\n *\n * @param paths - Array of paths to texture files\n * @returns Object containing textures, loading state, and error state\n */\nexport function useTextures(paths: MaybeRef<string[]>) {\n  // Create a ref to track error state\n  const error = ref<Error | null>(null)\n\n  // Unwrap the MaybeRef to get the actual array\n  const pathsArray = unref(paths)\n\n  // Load all textures\n  const results = pathsArray.map((path: string) => {\n    try {\n      const result = useLoader(TextureLoader, path, {\n        initialValue: new Texture(),\n      })\n      return result\n    }\n    catch (err) {\n      error.value = err as Error\n      return ref(null)\n    }\n  })\n\n  // Create a computed property for the loaded textures\n  const loadedTextures = computed(() => {\n    return results\n      .map((result) => {\n        if (result && 'state' in result) {\n          return result.state.value\n        }\n        return null\n      })\n      .filter(Boolean) as Texture[]\n  })\n\n  // Compute loading state based on all results\n  const isLoading = computed(() => {\n    // Check if any texture is still loading\n    return results.some((result) => {\n      if (result && 'isLoading' in result) {\n        return result.isLoading.value\n      }\n      return false\n    })\n  })\n\n  // Compute combined error\n  const combinedError = computed(() => {\n    const errors: Error[] = []\n\n    results.forEach((result) => {\n      if (result && 'error' in result && result.error) {\n        // Safely cast the error to Error type\n        const err = result.error\n        if (err instanceof Error) {\n          errors.push(err)\n        }\n        else if (typeof err === 'object' && err !== null && 'message' in err) {\n          // Create a new Error from the error object\n          errors.push(new Error(String(err.message)))\n        }\n      }\n    })\n\n    if (error.value) {\n      errors.push(error.value)\n    }\n\n    return errors.length > 0 ? errors : null\n  })\n\n  return {\n    textures: loadedTextures,\n    isLoading,\n    error: combinedError,\n  }\n}\n"
  },
  {
    "path": "src/core/loaders/useVideoTexture.ts",
    "content": "import { logError } from '@tresjs/core'\nimport { VideoTexture } from 'three'\n\ninterface VideoTextureProps extends HTMLVideoElement {\n  unsuspend?: 'canplay' | 'canplaythrough' | 'loadstart' | 'loadedmetadata'\n  start?: boolean\n}\n\n/**\n * Composable for loading video textures.\n *\n * ```ts\n * import { ref } from 'vue'\n * import { useVideoTexture } from '@tresjs/cientos'\n * import MyVideo from 'MyVideo.mp4'\n *\n * const texture = ref()\n * texture.value = await useVideoTexture(MyVideo)\n * ```\n * Then you can use the texture in your material.\n *\n * ```vue\n * <TresMeshBasicMaterial :map=\"texture\" />\n * ```\n * @see https://threejs.org/docs/index.html?q=video#api/en/textures/VideoTexture\n * @export\n * @param {HTMLVideoElement} src\n * @return {VideoTexture}  {VideoTexture}\n */\nexport async function useVideoTexture(src: string | MediaStream, options?: Partial<VideoTextureProps>) {\n  /**\n   * Load a video as a texture.\n   *\n   * @param {src} string\n   * @return {VideoTexture}  {VideoTexture}\n   */\n  if (!src) { return logError('Error no path provided') }\n\n  const { unsuspend, start, crossOrigin, muted, loop, ...rest } = {\n    unsuspend: 'loadedmetadata',\n    crossOrigin: 'Anonymous',\n    muted: true,\n    loop: true,\n    start: true,\n    playsInline: true,\n    ...options,\n  }\n\n  function loadTexture(): Promise<VideoTexture> {\n    return new Promise((resolve, reject) => {\n      const video = Object.assign(document.createElement('video'), {\n        src: (typeof src === 'string' && src) || undefined,\n        crossOrigin,\n        loop,\n        muted,\n        autoplay: true,\n        ...rest,\n      })\n      const texture = new VideoTexture(video)\n      video.addEventListener(unsuspend, () => resolve(texture))\n      video.addEventListener('error', () => reject(new Error('Error loading video')))\n      return texture\n    })\n  }\n  try {\n    const texture = await loadTexture()\n    if (start && texture.image) { texture.image.play() }\n    return texture\n  }\n  catch {\n    logError('Error loading resource')\n  }\n}\n"
  },
  {
    "path": "src/core/materials/customShaderMaterial/index.vue",
    "content": "<script setup lang=\"ts\">\nimport { useTres } from '@tresjs/core'\nimport CustomShaderMaterial from 'three-custom-shader-material/vanilla'\nimport { shallowRef, watch } from 'vue'\nimport type { Fn } from '@vueuse/core'\n\ninterface CustomShaderMaterialProps {\n  baseMaterial: Fn\n  vertexShader?: string\n  fragmentShader?: string\n  silent?: boolean\n  uniforms?: { [uniform: string]: any }\n}\n\nconst props = defineProps<CustomShaderMaterialProps>()\n\nconst customShaderMaterialClass = shallowRef(null)\n\nconst { extend, invalidate } = useTres()\nextend({ CustomShaderMaterial })\nwatch(props, () => {\n  invalidate()\n})\n\ndefineExpose({ instance: customShaderMaterialClass })\n</script>\n\n<template>\n  <TresCustomShaderMaterial\n    ref=\"customShaderMaterialClass\"\n    :args=\"[props]\"\n  />\n</template>\n"
  },
  {
    "path": "src/core/materials/holographicMaterial/HolographicMaterialParameters.ts",
    "content": "import {\n  AdditiveBlending,\n  Clock,\n  Color,\n  FrontSide,\n  ShaderMaterial,\n  Uniform,\n} from 'three'\nimport type { Blending, Side } from 'three'\n\ninterface HolographicMaterialParameters {\n  time?: number\n  fresnelOpacity?: number\n  fresnelAmount?: number\n  scanlineSize?: number\n  hologramBrightness?: number\n  signalSpeed?: number\n  hologramColor?: Color\n  enableBlinking?: boolean\n  blinkFresnelOnly?: boolean\n  hologramOpacity?: number\n  blendMode?: Blending\n  side?: Side\n  depthTest?: boolean\n}\nclass HolographicMaterial extends ShaderMaterial {\n  clock: Clock\n  /**\n   * Create a HolographicMaterial.\n   *\n   * @param {object} parameters - The parameters to configure the material.\n   * @param {number} [parameters.time] - The time uniform representing animation time.\n   * @param {number} [parameters.fresnelOpacity] - The opacity for the fresnel effect.\n   * @param {number} [parameters.fresnelAmount] - The strength of the fresnel effect.\n   * @param {number} [parameters.scanlineSize] - The size of the scanline effect.\n   * @param {number} [parameters.hologramBrightness] - The brightness of the hologram.\n   * @param {number} [parameters.signalSpeed] - The speed of the signal effect.\n   * @param {Color} [parameters.hologramColor] - The color of the hologram.\n   * @param {boolean} [parameters.enableBlinking] - Enable/disable blinking effect.\n   * @param {boolean} [parameters.blinkFresnelOnly] - Enable blinking only on the fresnel effect.\n   * @param {number} [parameters.hologramOpacity] - The opacity of the hologram.\n   * @param {number} [parameters.blendMode] - The blending mode. Use `THREE.NormalBlending` or `THREE.AdditiveBlending`.\n   * @param {number} [parameters.side] - The rendering side. Use `THREE.FrontSide`,\n   *  `THREE.BackSide`, or `THREE.DoubleSide`.\n   * @param {boolean} [parameters.depthTest] - Enable or disable depthTest.\n   */\n  constructor(parameters: HolographicMaterialParameters = {}) {\n    super()\n\n    this.vertexShader /* GLSL */\n      = `\n      #define STANDARD\n      varying vec3 vViewPosition;\n      #ifdef USE_TRANSMISSION\n      varying vec3 vWorldPosition;\n      #endif\n    \n      varying vec2 vUv;\n      varying vec4 vPos;\n      varying vec3 vNormalW;\n      varying vec3 vPositionW;\n\n      #include <common>\n      #include <uv_pars_vertex>\n      #include <envmap_pars_vertex>\n      #include <color_pars_vertex>\n      #include <fog_pars_vertex>\n      #include <morphtarget_pars_vertex>\n      #include <skinning_pars_vertex>\n      #include <logdepthbuf_pars_vertex>\n      #include <clipping_planes_pars_vertex>\n\n      void main() {\n        \n        #include <uv_vertex>\n        #include <color_vertex>\n        #include <morphcolor_vertex>\n      \n        #if defined ( USE_ENVMAP ) || defined ( USE_SKINNING )\n      \n          #include <beginnormal_vertex>\n          #include <morphnormal_vertex>\n          #include <skinbase_vertex>\n          #include <skinnormal_vertex>\n          #include <defaultnormal_vertex>\n      \n        #endif\n      \n        #include <begin_vertex>\n        #include <morphtarget_vertex>\n        #include <skinning_vertex>\n        #include <project_vertex>\n        #include <logdepthbuf_vertex>\n        #include <clipping_planes_vertex>\n      \n        #include <worldpos_vertex>\n        #include <envmap_vertex>\n        #include <fog_vertex>\n\n        mat4 modelViewProjectionMatrix = projectionMatrix * modelViewMatrix;\n\n        vUv = uv;\n        vPos = projectionMatrix * modelViewMatrix * vec4( transformed, 1.0 );\n        vPositionW = vec3( vec4( transformed, 1.0 ) * modelMatrix);\n        vNormalW = normalize( vec3( vec4( normal, 0.0 ) * modelMatrix ) );\n        \n        gl_Position = modelViewProjectionMatrix * vec4( transformed, 1.0 );\n\n      }`\n\n    this.fragmentShader /* GLSL */\n      = ` \n      varying vec2 vUv;\n      varying vec3 vPositionW;\n      varying vec4 vPos;\n      varying vec3 vNormalW;\n      \n      uniform float time;\n      uniform float fresnelOpacity;\n      uniform float scanlineSize;\n      uniform float fresnelAmount;\n      uniform float signalSpeed;\n      uniform float hologramBrightness;\n      uniform float hologramOpacity;\n      uniform bool blinkFresnelOnly;\n      uniform bool enableBlinking;\n      uniform vec3 hologramColor;\n\n      float flicker( float amt, float time ) {return clamp( fract( cos( time ) * 43758.5453123 ), amt, 1.0 );}\n      float random(in float a, in float b) { return fract((cos(dot(vec2(a,b) ,vec2(12.9898,78.233))) * 43758.5453)); }\n\n      void main() {\n        vec2 vCoords = vPos.xy;\n        vCoords /= vPos.w;\n        vCoords = vCoords * 0.5 + 0.5;\n        vec2 myUV = fract( vCoords );\n\n        // Defines hologram main color\n        vec4 hologramColor = vec4(hologramColor, mix(hologramBrightness, vUv.y, 0.5));\n\n        // Add scanlines\n        float scanlines = 10.;\n        scanlines += 20. * sin(time *signalSpeed * 20.8 - myUV.y * 60. * scanlineSize);\n        scanlines *= smoothstep(1.3 * cos(time *signalSpeed + myUV.y * scanlineSize), 0.78, 0.9);\n        scanlines *= max(0.25, sin(time *signalSpeed) * 1.0);\n\n        // Scanlines offsets\n        float r = random(vUv.x, vUv.y);\n        float g = random(vUv.y * 20.2, vUv.y * .2);\n        float b = random(vUv.y * .9, vUv.y * .2);\n\n        // Scanline composition\n        hologramColor += vec4(r*scanlines, b*scanlines, r, 1.0) / 84.;\n        vec4 scanlineMix = mix(vec4(0.0), hologramColor, hologramColor.a);\n\n        // Calculates fresnel\n        vec3 viewDirectionW = normalize(cameraPosition - vPositionW);\n        float fresnelEffect = dot(viewDirectionW, vNormalW) * (1.6 - fresnelOpacity/2.);\n        fresnelEffect = clamp(fresnelAmount - fresnelEffect, 0., fresnelOpacity);\n\n        // Blinkin effect\n        //Suggested by Octano - https://x.com/OtanoDesign?s=20\n        float blinkValue = enableBlinking ? 0.6 - signalSpeed : 1.0;\n        float blink = flicker(blinkValue, time * signalSpeed * .02);\n\n        // Final shader composition\n        vec3 finalColor;\n\n        if(blinkFresnelOnly){\n          finalColor = scanlineMix.rgb + fresnelEffect * blink;\n        }else{\n          finalColor = scanlineMix.rgb * blink + fresnelEffect;\n        }\n\n        gl_FragColor = vec4( finalColor, hologramOpacity);\n\n      }`\n\n    // Set default values or modify existing properties if needed\n    this.uniforms = {\n      /**\n       * The time uniform representing animation time.\n       * @type {Uniform<number>}\n       * @default 0.0\n       */\n      time: new Uniform(0),\n\n      /**\n       * The opacity for the fresnel effect.\n       * @type {Uniform<number>}\n       * @default 1.0\n       */\n      fresnelOpacity: new Uniform(parameters.fresnelOpacity !== undefined ? parameters.fresnelOpacity : 1),\n\n      /**\n       * The strength of the fresnel effect.\n       * @type {Uniform<number>}\n       * @default 1.0\n       */\n      fresnelAmount: new Uniform(parameters.fresnelAmount !== undefined ? parameters.fresnelAmount : 0.45),\n\n      /**\n       * The size of the scanline effect.\n       * @type {Uniform<number>}\n       * @default 1.0\n       */\n      scanlineSize: new Uniform(parameters.scanlineSize !== undefined ? parameters.scanlineSize : 8),\n\n      /**\n       * The brightness of the hologram.\n       * @type {Uniform<number>}\n       * @default 1.0\n       */\n      hologramBrightness: new Uniform(parameters.hologramBrightness !== undefined\n        ? parameters.hologramBrightness\n        : 1),\n\n      /**\n       * The speed of the signal effect.\n       * @type {Uniform<number>}\n       * @default 1.0\n       */\n      signalSpeed: new Uniform(parameters.signalSpeed !== undefined ? parameters.signalSpeed : 1),\n\n      /**\n       * The color of the hologram.\n       * @type {Uniform<Color>}\n       * @default new Color(0xFFFFFF)\n       */\n      hologramColor: new Uniform(parameters.hologramColor !== undefined\n        ? new Color(parameters.hologramColor)\n        : new Color('#00d5ff')),\n\n      /**\n       * Enable/disable blinking effect.\n       * @type {Uniform<boolean>}\n       * @default true\n       */\n      enableBlinking: new Uniform(parameters.enableBlinking !== undefined ? parameters.enableBlinking : true),\n\n      /**\n       * Enable blinking only on the fresnel effect.\n       * @type {Uniform<boolean>}\n       * @default false\n       */\n      blinkFresnelOnly: new Uniform(parameters.blinkFresnelOnly !== undefined ? parameters.blinkFresnelOnly : true),\n\n      /**\n       * The opacity of the hologram.\n       * @type {Uniform<number>}\n       * @default 1.0\n       */\n      hologramOpacity: new Uniform(parameters.hologramOpacity !== undefined ? parameters.hologramOpacity : 1),\n    }\n\n    this.clock = new Clock()\n    this.setValues(parameters)\n    this.depthTest = parameters.depthTest !== undefined ? parameters.depthTest : false\n    this.blending = parameters.blendMode !== undefined ? parameters.blendMode : AdditiveBlending\n    this.transparent = true\n    this.side = parameters.side !== undefined ? parameters.side : FrontSide\n  }\n\n  update() {\n    this.uniforms.time.value = this.clock.getElapsedTime()\n  }\n}\nexport default HolographicMaterial\n"
  },
  {
    "path": "src/core/materials/holographicMaterial/index.vue",
    "content": "<script setup lang=\"ts\">\nimport { useLoop, useTresContext } from '@tresjs/core'\nimport { FrontSide } from 'three'\nimport { shallowRef } from 'vue'\nimport type { TresColor } from '@tresjs/core'\nimport type { Side } from 'three'\n\nimport HolographicMaterial from './HolographicMaterialParameters'\n\nconst props = withDefaults(\n  defineProps<{\n    fresnelAmount?: number\n    fresnelOpacity?: number\n    blinkFresnelOnly?: boolean\n    enableBlinking?: boolean\n    enableAdditive?: boolean\n    hologramBrightness?: number\n    scanlineSize?: number\n    signalSpeed?: number\n    hologramOpacity?: number\n    hologramColor?: TresColor\n    side?: Side\n  }>(),\n  {\n    fresnelAmount: 0.45,\n    fresnelOpacity: 1.0,\n    blinkFresnelOnly: true,\n    enableBlinking: true,\n    enableAdditive: true,\n    hologramBrightness: 0.7,\n    scanlineSize: 8.0,\n    signalSpeed: 0.45,\n    hologramOpacity: 1.0,\n    hologramColor: '#00d5ff',\n    side: FrontSide,\n  },\n)\n\nconst MeshHolographicMaterialClass = shallowRef()\n\nconst { extend } = useTresContext()\n\nextend({ HolographicMaterial })\n\ndefineExpose({ root: MeshHolographicMaterialClass, constructor: HolographicMaterial })\n\nconst { onBeforeRender } = useLoop()\n\nonBeforeRender(() => {\n  MeshHolographicMaterialClass.value?.update()\n  // TODO: comment this until invalidate is back in the loop callback on v5\n  // invalidate()\n})\n</script>\n\n<template>\n  <TresHolographicMaterial\n    ref=\"MeshHolographicMaterialClass\"\n    :uniforms-fresnelAmount-value=\"props.fresnelAmount\"\n    :uniforms-enableBlinking-value=\"props.enableBlinking\"\n    :uniforms-fresnelOpacity-value=\"props.fresnelOpacity\"\n    :uniforms-hologramBrightness-value=\"props.hologramBrightness\"\n    :uniforms-scanlineSize-value=\"props.scanlineSize\"\n    :uniforms-signalSpeed-value=\"props.signalSpeed\"\n    :uniforms-hologramColor-value=\"props.hologramColor\"\n    :uniforms-hologramOpacity-value=\"props.hologramOpacity\"\n    :uniforms-blinkFresnelOnly-value=\"props.blinkFresnelOnly\"\n    :enableAdditive=\"props.enableAdditive\"\n    :side=\"props.side\"\n  />\n</template>\n"
  },
  {
    "path": "src/core/materials/holographicMaterial/material.ts",
    "content": "/**\n * Holographic material by Anderson Mancini - Dec 2023.\n */\n\n/**\n\n  MIT License\n\n  Copyright (c) 2023 Anderson Mancini\n\n  Permission is hereby granted, free of charge, to any person obtaining a copy\n  of this software and associated documentation files (the \"Software\"), to deal\n  in the Software without restriction, including without limitation the rights\n  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  copies of the Software, and to permit persons to whom the Software is\n  furnished to do so, subject to the following conditions:\n\n  The above copyright notice and this permission notice shall be included in all\n  copies or substantial portions of the Software.\n\n  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n  SOFTWARE.\n */\n"
  },
  {
    "path": "src/core/materials/index.ts",
    "content": "import CustomShaderMaterial from './customShaderMaterial/index.vue'\nimport HolographicMaterial from './holographicMaterial/index.vue'\nimport MeshDiscardMaterial from './meshDiscardMaterial/index.vue'\nimport MeshGlassMaterial from './meshGlassMaterial/index.vue'\nimport MeshReflectionMaterial from './meshReflectionMaterial/index.vue'\nimport MeshWobbleMaterial from './meshWobbleMaterial/index.vue'\nimport PointMaterial from './pointMaterial/component.vue'\n\nexport {\n  CustomShaderMaterial,\n  HolographicMaterial,\n  MeshDiscardMaterial,\n  MeshGlassMaterial,\n  MeshReflectionMaterial,\n  MeshWobbleMaterial,\n  PointMaterial,\n}\n"
  },
  {
    "path": "src/core/materials/meshDiscardMaterial/index.vue",
    "content": "<script setup lang=\"ts\">\nimport { useTresContext } from '@tresjs/core'\nimport { shallowRef } from 'vue'\nimport { MeshDiscardMaterial } from './material'\n\nconst meshDiscardMaterialRef = shallowRef()\n\nconst { extend } = useTresContext()\n\nextend({ MeshDiscardMaterial })\n\ndefineExpose({ instance: meshDiscardMaterialRef })\n</script>\n\n<template>\n  <TresMeshDiscardMaterial ref=\"meshDiscardMaterialRef\" />\n</template>\n"
  },
  {
    "path": "src/core/materials/meshDiscardMaterial/material.ts",
    "content": "import { ShaderMaterial } from 'three'\n\nexport class MeshDiscardMaterial extends ShaderMaterial {\n  constructor() {\n    super()\n    this.vertexShader = 'void main() { }'\n    this.fragmentShader = 'void main() { gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0); discard;}'\n  }\n}\n"
  },
  {
    "path": "src/core/materials/meshGlassMaterial/index.vue",
    "content": "<script setup lang=\"ts\">\nimport { useTresContext } from '@tresjs/core'\nimport { shallowRef } from 'vue'\n\nimport MeshGlassMaterial from './material'\n\nconst MeshGlassMaterialClass = shallowRef()\n\nconst { extend } = useTresContext()\n\nextend({ MeshGlassMaterial })\n\ndefineExpose({ instance: MeshGlassMaterialClass })\n</script>\n\n<template>\n  <TresMeshGlassMaterial ref=\"MeshGlassMaterialClass\" />\n</template>\n"
  },
  {
    "path": "src/core/materials/meshGlassMaterial/material.ts",
    "content": "import type { MeshStandardMaterialParameters } from 'three'\nimport { Color, MathUtils, MeshStandardMaterial, Vector2 } from 'three'\n\n// Extend Three.js types to include properties that exist at runtime but aren't in the type definitions\ndeclare module 'three' {\n  interface Material {\n    defines: Record<string, string | number | boolean>\n  }\n}\n\n// Create a properly typed interface for our glass material\ninterface IMeshGlassMaterial extends MeshStandardMaterial {\n  defines: Record<string, string | number | boolean>\n  version: number\n}\n\nclass MeshGlassMaterial extends MeshStandardMaterial implements IMeshGlassMaterial {\n  isMeshPhysicalMaterial: boolean\n  clearcoatMap: null\n  clearcoatRoughness: number\n  clearcoatRoughnessMap: null\n  clearcoatNormalScale: Vector2\n  clearcoatNormalMap: null\n  ior: number\n  transmissionMap: null\n  thickness: number\n  thicknessMap: null\n  attenuationDistance: number\n  attenuationColor: Color\n  specularIntensity: number\n  specularIntensityMap: null\n  specularColor: Color\n  specularColorMap: null\n  _clearcoat: number\n  _transmission: number\n\n  constructor(parameters: MeshStandardMaterialParameters = {}) {\n    super()\n\n    this.isMeshPhysicalMaterial = true\n\n    this.defines = {\n      STANDARD: '',\n      PHYSICAL: '',\n    }\n\n    this.clearcoatMap = null\n    this.clearcoatRoughness = 0.0\n    this.clearcoatRoughnessMap = null\n    this.clearcoatNormalScale = new Vector2(1, 1)\n    this.clearcoatNormalMap = null\n\n    this.ior = 1.5\n\n    Object.defineProperty(this, 'reflectivity', {\n      get() {\n        return MathUtils.clamp((2.5 * (this.ior - 1)) / (this.ior + 1), 0, 1)\n      },\n      set(reflectivity) {\n        this.ior = (1 + 0.4 * reflectivity) / (1 - 0.4 * reflectivity)\n      },\n    })\n    this.roughness = 0\n\n    this.transmissionMap = null\n\n    this.thickness = 0.5\n    this.thicknessMap = null\n    this.attenuationDistance = Number.POSITIVE_INFINITY\n    this.attenuationColor = new Color(1, 1, 1)\n\n    this.specularIntensity = 1.0\n    this.specularIntensityMap = null\n    this.specularColor = new Color(1, 1, 1)\n    this.specularColorMap = null\n\n    this._clearcoat = 0.5\n    this._transmission = 1\n\n    this.setValues(parameters)\n  }\n\n  get clearcoat() {\n    return this._clearcoat\n  }\n\n  set clearcoat(value) {\n    // eslint-disable-next-line style/no-mixed-operators\n    if (this._clearcoat > 0 !== value > 0) {\n      // Increment version to trigger shader recompilation - using mutable interface\n      ;(this as IMeshGlassMaterial).version++\n    }\n\n    this._clearcoat = value\n  }\n\n  get transmission() {\n    return this._transmission\n  }\n\n  set transmission(value) {\n    // eslint-disable-next-line style/no-mixed-operators\n    if (this._transmission > 0 !== value > 0) {\n      // Increment version to trigger shader recompilation - using mutable interface\n      ;(this as IMeshGlassMaterial).version++\n    }\n\n    this._transmission = value\n  }\n\n  copy(source: MeshGlassMaterial) {\n    super.copy(source)\n\n    this.defines = {\n      STANDARD: '',\n      PHYSICAL: '',\n    }\n\n    this.clearcoat = source.clearcoat\n    this.clearcoatMap = source.clearcoatMap\n    this.clearcoatRoughness = source.clearcoatRoughness\n    this.clearcoatRoughnessMap = source.clearcoatRoughnessMap\n    this.clearcoatNormalMap = source.clearcoatNormalMap\n    this.clearcoatNormalScale.copy(source.clearcoatNormalScale)\n\n    this.ior = source.ior\n\n    this.transmission = source.transmission\n    this.transmissionMap = source.transmissionMap\n\n    this.thickness = source.thickness\n    this.thicknessMap = source.thicknessMap\n    this.attenuationDistance = source.attenuationDistance\n    this.attenuationColor.copy(source.attenuationColor)\n\n    this.specularIntensity = source.specularIntensity\n    this.specularIntensityMap = source.specularIntensityMap\n    this.specularColor.copy(source.specularColor)\n    this.specularColorMap = source.specularColorMap\n\n    return this\n  }\n}\n\nexport default MeshGlassMaterial\n"
  },
  {
    "path": "src/core/materials/meshReflectionMaterial/BlurPass.ts",
    "content": "/*\nAdapted from Drei BlurPass\nhttps://github.com/pmndrs/drei/blob/master/\n\nMIT License\n\nCopyright (c) 2020 react-spring\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n*/\n\nimport {\n  BufferAttribute,\n  BufferGeometry,\n  Camera,\n  HalfFloatType,\n  LinearFilter,\n  Mesh,\n  Scene,\n  Vector2,\n  WebGLRenderTarget,\n} from 'three'\nimport type { Material, WebGLRenderer } from 'three'\n\nimport { ConvolutionMaterial } from './ConvolutionMaterial'\n\nexport interface BlurPassProps {\n  resolution: number\n  width?: number\n  height?: number\n  depthEdge0?: number\n  depthEdge1?: number\n  depthScale?: number\n  depthBias?: number\n}\n\nexport class BlurPass {\n  readonly renderTargetA: WebGLRenderTarget\n  readonly renderTargetB: WebGLRenderTarget\n  readonly convolutionMaterial: ConvolutionMaterial\n  readonly scene: Scene\n  readonly camera: Camera\n  readonly screen: Mesh\n  renderToScreen: boolean = false\n\n  constructor({\n    resolution,\n    width = 500,\n    height = 500,\n    depthEdge0 = 0,\n    depthEdge1 = 1,\n    depthScale = 0,\n    depthBias = 0.25,\n  }: BlurPassProps) {\n    this.renderTargetA = new WebGLRenderTarget(resolution, resolution, {\n      minFilter: LinearFilter,\n      magFilter: LinearFilter,\n      stencilBuffer: false,\n      depthBuffer: false,\n      type: HalfFloatType,\n    })\n    this.renderTargetB = this.renderTargetA.clone()\n    this.convolutionMaterial = new ConvolutionMaterial()\n    this.convolutionMaterial.setTexelSize(1.0 / width, 1.0 / height)\n    this.convolutionMaterial.setResolution(new Vector2(width, height))\n    this.scene = new Scene()\n    this.camera = new Camera()\n    this.convolutionMaterial.uniforms.depthEdge0.value = depthEdge0\n    this.convolutionMaterial.uniforms.depthEdge1.value = depthEdge1\n    this.convolutionMaterial.uniforms.depthScale.value = depthScale\n    this.convolutionMaterial.uniforms.depthBias.value = depthBias\n    this.convolutionMaterial.defines.USE_DEPTH = depthScale > 0\n    const vertices = new Float32Array([-1, -1, 0, 3, -1, 0, -1, 3, 0])\n    const uvs = new Float32Array([0, 0, 2, 0, 0, 2])\n    const geometry = new BufferGeometry()\n    geometry.setAttribute('position', new BufferAttribute(vertices, 3))\n    geometry.setAttribute('uv', new BufferAttribute(uvs, 2))\n    this.screen = new Mesh(geometry, this.convolutionMaterial)\n    this.screen.frustumCulled = false\n    this.scene.add(this.screen)\n  }\n\n  render(renderer: WebGLRenderer, inputBuffer: WebGLRenderTarget, outputBuffer: WebGLRenderTarget) {\n    const scene = this.scene\n    const camera = this.camera\n    const renderTargetA = this.renderTargetA\n    const renderTargetB = this.renderTargetB\n    const material = this.convolutionMaterial\n    const uniforms = material.uniforms\n    uniforms.depthBuffer.value = inputBuffer.depthTexture\n    const kernel = material.kernel\n    let lastRT = inputBuffer\n    let destRT\n    let i, l\n    // Apply the multi-pass blur.\n    for (i = 0, l = kernel.length - 1; i < l; ++i) {\n      // Alternate between targets.\n      destRT = (i & 1) === 0 ? renderTargetA : renderTargetB\n      uniforms.kernel.value = kernel[i]\n      uniforms.inputBuffer.value = lastRT.texture\n      renderer.setRenderTarget(destRT)\n      renderer.render(scene, camera)\n      lastRT = destRT\n    }\n    uniforms.kernel.value = kernel[i]\n    uniforms.inputBuffer.value = lastRT.texture\n    renderer.setRenderTarget(this.renderToScreen ? null : outputBuffer)\n    renderer.render(scene, camera)\n  }\n\n  dispose() {\n    (this.screen.material as Material).dispose()\n    this.screen.geometry.dispose()\n    this.renderTargetA.dispose()\n    this.renderTargetB.dispose()\n    this.convolutionMaterial.dispose()\n  }\n}\n"
  },
  {
    "path": "src/core/materials/meshReflectionMaterial/ConvolutionMaterial.ts",
    "content": "/*\nAdapted from Drei ConvolutionMaterial\nhttps://github.com/pmndrs/drei/blob/master/\n\nMIT License\n\nCopyright (c) 2020 react-spring\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n*/\n\nimport { NoBlending, ShaderMaterial, Uniform, Vector2 } from 'three'\nimport { version } from '../../../utils/constants'\n\nexport class ConvolutionMaterial extends ShaderMaterial {\n  readonly kernel: Float32Array\n  constructor(texelSize = new Vector2()) {\n    super({\n      uniforms: {\n        inputBuffer: new Uniform(null),\n        depthBuffer: new Uniform(null),\n        resolution: new Uniform(new Vector2()),\n        texelSize: new Uniform(new Vector2()),\n        halfTexelSize: new Uniform(new Vector2()),\n        kernel: new Uniform(0.0),\n        scale: new Uniform(1.0),\n        cameraNear: new Uniform(0.0),\n        cameraFar: new Uniform(1.0),\n        depthEdge0: new Uniform(0.0),\n        depthEdge1: new Uniform(1.0),\n        depthScale: new Uniform(0.0),\n        depthBias: new Uniform(0.25),\n      },\n      fragmentShader: `#include <common>\n        #include <dithering_pars_fragment>      \n        uniform sampler2D inputBuffer;\n        uniform sampler2D depthBuffer;\n        uniform float cameraNear;\n        uniform float cameraFar;\n        uniform float depthEdge0;\n        uniform float depthEdge1;\n        uniform float depthScale;\n        uniform float depthBias;\n        varying vec2 vUv;\n        varying vec2 vUv0;\n        varying vec2 vUv1;\n        varying vec2 vUv2;\n        varying vec2 vUv3;\n\n        void main() {\n          float depthFactor = 0.0;\n          \n          #ifdef USE_DEPTH\n            vec4 depth = texture2D(depthBuffer, vUv);\n            depthFactor = smoothstep(\n              1.0 - depthEdge1, 1.0 - depthEdge0,\n              1.0 - (depth.r * depth.a) + depthBias\n            );\n            depthFactor = clamp(depthScale * depthFactor + 0.25, 0.0, 1.0);\n          #endif\n\n          gl_FragColor = 0.25 * (\n            texture2D(inputBuffer, mix(vUv0, vUv, depthFactor))\n            + texture2D(inputBuffer, mix(vUv1, vUv, depthFactor))\n            + texture2D(inputBuffer, mix(vUv2, vUv, depthFactor))\n            + texture2D(inputBuffer, mix(vUv3, vUv, depthFactor))\n          );\n          \n          #include <dithering_fragment>\n          #include <tonemapping_fragment>\n          #include <${version >= 154 ? 'colorspace_fragment' : 'encodings_fragment'}>\n        }`,\n      vertexShader: `uniform vec2 texelSize;\n        uniform vec2 halfTexelSize;\n        uniform float kernel;\n        uniform float scale;\n        varying vec2 vUv;\n        varying vec2 vUv0;\n        varying vec2 vUv1;\n        varying vec2 vUv2;\n        varying vec2 vUv3;\n\n        void main() {\n          vec2 uv = position.xy * 0.5 + 0.5;\n          vUv = uv;\n\n          vec2 dUv = (texelSize * vec2(kernel) + halfTexelSize) * scale;\n          vUv0 = vec2(uv.x - dUv.x, uv.y + dUv.y);\n          vUv1 = vec2(uv.x + dUv.x, uv.y + dUv.y);\n          vUv2 = vec2(uv.x + dUv.x, uv.y - dUv.y);\n          vUv3 = vec2(uv.x - dUv.x, uv.y - dUv.y);\n\n          gl_Position = vec4(position.xy, 1.0, 1.0);\n        }`,\n      blending: NoBlending,\n      depthWrite: false,\n      depthTest: false,\n    })\n\n    this.toneMapped = false\n    this.setTexelSize(texelSize.x, texelSize.y)\n    this.kernel = new Float32Array([0.0, 1.0, 2.0, 2.0, 3.0])\n  }\n\n  setTexelSize(x: number, y: number) {\n    this.uniforms.texelSize.value.set(x, y)\n    this.uniforms.halfTexelSize.value.set(x, y).multiplyScalar(0.5)\n  }\n\n  setResolution(resolution: Vector2) {\n    this.uniforms.resolution.value.copy(resolution)\n  }\n}\n"
  },
  {
    "path": "src/core/materials/meshReflectionMaterial/index.vue",
    "content": "<!-- eslint-disable vue/attribute-hyphenation -->\n<script setup lang=\"ts\">\nimport { logWarning, useLoop, useTres } from '@tresjs/core'\nimport type {\n  Texture,\n} from 'three'\nimport {\n  Color,\n  DepthTexture,\n  Euler,\n  HalfFloatType,\n  LinearFilter,\n  Matrix4,\n  PerspectiveCamera,\n  Plane,\n  TangentSpaceNormalMap,\n  Vector2,\n  Vector3,\n  Vector4,\n  WebGLRenderer,\n  WebGLRenderTarget,\n} from 'three'\nimport { computed, onBeforeUnmount, shallowRef, toValue, watch } from 'vue'\nimport type { TresColor } from '@tresjs/core'\nimport { BlurPass } from './BlurPass'\nimport { MeshReflectionMaterial } from './material'\nimport { WebGPURenderer } from 'three/webgpu'\n\nexport interface MeshReflectionMaterialProps {\n\n  /** Length in pixels of one side of the square reflective textures. */\n  resolution?: number\n  /** Overall strength of the reflection. */\n  mix?: number\n\n  /** Strength of the sharp reflection on smooth surfaces. */\n  sharpMix?: number\n  /** Sharp reflection can be faded out by depth – distance from the reflective surface. Performance note: if the value is greater than `0`, a depth texture will be created. */\n  sharpDepthScale?: number\n  /** Sharp reflection depth falloff bias. */\n  sharpDepthBias?: number\n  /** Sharp reflection depth falloff start. */\n  sharpDepthEdgeMin?: number\n  /** Sharp reflection depth falloff end. */\n  sharpDepthEdgeMax?: number\n\n  /** Strength of the blurred reflection on smooth surfaces. */\n  blurMixSmooth?: number\n  /** Strength of the blurred reflection on rough surfaces. */\n  blurMixRough?: number\n  /** Blurred reflection can spread out by depth – distance from the reflective surface. Performance note: if the value is greater than `0`, depth texture will be rendered. */\n  blurDepthScale?: number\n  /** Blurred reflection depth spread bias. */\n  blurDepthBias?: number\n  /** Blurred reflection depth spread start. */\n  blurDepthEdgeMin?: number\n  /** Blurred reflection depth spread end. */\n  blurDepthEdgeMax?: number\n  /** Size of the blur. If `[number, number]`, first number is width, second is height. Performance note: if other than `[0, 0]` or `0`, a blur texture will be rendered. */\n  blurSize?: [number, number] | number\n\n  /** Texture for offsetting the reflection. */\n  distortionMap?: Texture\n  /** Influence of `distortionMap`. */\n  distortion?: number\n  /** Offsets the reflection. */\n  reflectorOffset?: number\n\n  color?: TresColor\n  roughness?: number\n  metalness?: number\n  map?: Texture\n  lightMap?: Texture\n  lightMapIntensity?: number\n  aoMap?: Texture | null\n  aoMapIntensity?: number\n  emissive?: TresColor\n  emissiveIntensity?: number\n  emissiveMap?: Texture\n  bumpMap?: Texture\n  bumpScale?: number\n  normalMap?: Texture\n  normalMapType?: number\n  normalScale?: Vector2\n  displacementMap?: Texture\n  displacementScale?: number\n  displacementBias?: number\n  roughnessMap?: Texture | null\n  metalnessMap?: Texture | null\n  alphaMap?: Texture | null\n  envMap?: Texture | null\n  envMapRotation?: Euler\n  envMapIntensity?: number\n  wireframe?: boolean\n  wireframeLinewidth?: number\n  wireframeLinecap?: string\n  wireframeLinejoin?: string\n  flatShading?: boolean\n  fog?: boolean\n}\nconst props = withDefaults(\n  defineProps<MeshReflectionMaterialProps>(),\n  {\n    resolution: 256,\n    mix: 1,\n\n    sharpMix: 1,\n    sharpDepthEdgeMin: 0.0,\n    sharpDepthEdgeMax: 0.2,\n    sharpDepthScale: 1,\n    sharpDepthBias: 0,\n\n    blurMixSmooth: 1,\n    blurMixRough: 1,\n    blurDepthEdgeMin: 0.0,\n    blurDepthEdgeMax: 0.2,\n    blurDepthScale: 1,\n    blurDepthBias: 0,\n    blurSize: () => [0, 0],\n\n    distortion: 0,\n    reflectorOffset: 0,\n\n    // NOTE: MeshStandardMaterial props\n    // If you try to simplify this file by removing the props below\n    // make sure that the fall-through props like 'roughnessMap' and\n    // 'normalMap' are actually falling through and visible in the material.\n    color: () => new Color(0x333333),\n    roughness: 1.0,\n    roughnessMap: null,\n    metalness: 0.0,\n    lightMapIntensity: 1.0,\n    aoMapIntensity: 1.0,\n    emissive: () => new Color(0x000000),\n    emissiveIntensity: 1.0,\n    bumpScale: 1,\n    normalMapType: TangentSpaceNormalMap,\n    normalScale: () => new Vector2(1, 1),\n    displacementScale: 1,\n    displacementBias: 0,\n    envMapRotation: () => new Euler(),\n    envMapIntensity: 1.0,\n    wireframe: false,\n    wireframeLinewidth: 1,\n    wireframeLinecap: 'round',\n    wireframeLinejoin: 'round',\n    flatShading: false,\n    fog: true,\n  },\n)\n\nconst { extend, invalidate } = useTres()\nextend({ MeshReflectionMaterial })\n\nconst blurWidth = computed(() => 500 - (Array.isArray(props.blurSize) ? props.blurSize[0] : props.blurSize))\nconst blurHeight = computed(() => 500 - (Array.isArray(props.blurSize) ? props.blurSize[1] : props.blurSize))\nconst hasBlur = computed(() => blurWidth.value > 0 || blurHeight.value > 0)\nconst hasDepth = computed(() => props.sharpDepthScale > 0 || props.blurDepthScale > 0)\nconst hasDistortion = computed(() => !!props.distortionMap)\nconst hasRoughness = computed(() => !!props.roughnessMap)\n\nconst materialRef = shallowRef()\nlet blurpass: BlurPass\n\nconst state = {\n  reflectorPlane: new Plane(),\n  normal: new Vector3(),\n  reflectorWorldPosition: new Vector3(),\n  cameraWorldPosition: new Vector3(),\n  rotationMatrix: new Matrix4(),\n  lookAtPosition: new Vector3(0, 0, -1),\n  clipPlane: new Vector4(),\n  view: new Vector3(),\n  target: new Vector3(),\n  q: new Vector4(),\n  virtualCamera: new PerspectiveCamera(),\n  textureMatrix: new Matrix4(),\n}\n\nconst fboSharp = new WebGLRenderTarget(\n  props.resolution,\n  props.resolution,\n  {\n    minFilter: LinearFilter,\n    magFilter: LinearFilter,\n    type: HalfFloatType,\n    depthBuffer: true,\n    depthTexture: new DepthTexture(\n      props.resolution,\n      props.resolution,\n    ),\n  },\n)\n\nconst fboBlur = new WebGLRenderTarget(\n  props.resolution,\n  props.resolution,\n  {\n    minFilter: LinearFilter,\n    magFilter: LinearFilter,\n    type: HalfFloatType,\n  },\n)\n\nwatch(\n  () => [props.resolution],\n  () => {\n    fboSharp.setSize(props.resolution, props.resolution)\n    fboBlur.setSize(props.resolution, props.resolution)\n  },\n)\n\nwatch(() => [\n  props.resolution,\n  blurWidth.value,\n  blurHeight.value,\n  props.blurDepthEdgeMin,\n  props.blurDepthEdgeMax,\n  props.blurDepthScale,\n  props.blurDepthBias,\n], () => {\n  blurpass?.dispose()\n  blurpass = new BlurPass({\n    resolution: props.resolution,\n    width: blurWidth.value,\n    height: blurHeight.value,\n    depthEdge0: props.blurDepthEdgeMin,\n    depthEdge1: props.blurDepthEdgeMax,\n    depthScale: props.blurDepthScale,\n    depthBias: props.blurDepthBias,\n  })\n}, { immediate: true })\n\n// NOTE: Begin #615 warning\n// The Tres core doesn't currently swap mesh materials when a\n// material component recompiles.\n//\n// Issue: https://github.com/Tresjs/tres/issues/615\n//\n// Workaround: Warn users if they trigger a recompile.\n//\n// TODO: This code can be removed when #615 is resolved\nwatch(() => [hasBlur.value], () => {\n  logWarning(\n    'MeshReflectionMaterial: Setting blurMixRough or blurMixSmooth to 0, then non-zero triggers a recompile.'\n    + 'The TresJS core cannot currently handle recompiled materials.',\n  )\n})\nwatch(hasDepth, () => {\n  logWarning(\n    'MeshReflectionMaterial: Setting depthScale to 0, then non-zero triggers a recompile.'\n    + 'The TresJS core cannot currently handle recompiled materials.',\n  )\n})\nwatch(hasDistortion, () => {\n  logWarning(\n    'MeshReflectionMaterial: Toggling distortionMap triggers a recompile.'\n    + 'The TresJS core cannot currently handle recompiled materials.',\n  )\n})\nwatch(hasRoughness, () => {\n  logWarning(\n    'MeshReflectionMaterial: Toggling roughnessMap triggers a recompile.'\n    + 'The TresJS core cannot currently handle recompiled materials.',\n  )\n})\nwatch(() => [props.normalMap], () => {\n  logWarning(\n    'MeshReflectionMaterial: Toggling normalMap triggers a recompile.'\n    + 'The TresJS core cannot currently handle recompiled materials.',\n  )\n})\n// End #615 warning\n\nonBeforeUnmount(() => {\n  fboSharp.dispose()\n  fboBlur.dispose()\n  blurpass.dispose()\n})\nconst { onBeforeRender } = useLoop()\n\nonBeforeRender(({ renderer, scene, camera }) => {\n  const parent = (materialRef.value as any)?.__tres?.parent\n  if (!parent) { return }\n  if (renderer instanceof WebGPURenderer) {\n    console.warn('MeshReflectionMaterial: WebGPURenderer is not supported yet')\n    return\n  }\n  if (renderer instanceof WebGLRenderer) {\n    invalidate()\n\n    const currentXrEnabled = renderer.xr.enabled\n    const currentShadowAutoUpdate = renderer.shadowMap.autoUpdate\n\n    state.reflectorWorldPosition.setFromMatrixPosition(parent.matrixWorld)\n    state.cameraWorldPosition.setFromMatrixPosition(camera.value?.matrixWorld as Matrix4)\n    state.rotationMatrix.extractRotation(parent.matrixWorld)\n    state.normal.set(0, 0, 1)\n    state.normal.applyMatrix4(state.rotationMatrix)\n    state.reflectorWorldPosition.addScaledVector(state.normal, props.reflectorOffset)\n    state.view.subVectors(state.reflectorWorldPosition, state.cameraWorldPosition)\n\n    // NOTE: Avoid rendering when reflector is facing away\n    if (state.view.dot(state.normal) > 0) { return }\n\n    // NOTE: Avoid re-rendering the reflective object.\n    parent.visible = false\n\n    state.view.reflect(state.normal).negate()\n    state.view.add(state.reflectorWorldPosition)\n    state.rotationMatrix.extractRotation(camera.value?.matrixWorld as Matrix4)\n    state.lookAtPosition.set(0, 0, -1)\n    state.lookAtPosition.applyMatrix4(state.rotationMatrix)\n    state.lookAtPosition.add(state.cameraWorldPosition)\n    state.target.subVectors(state.reflectorWorldPosition, state.lookAtPosition)\n    state.target.reflect(state.normal).negate()\n    state.target.add(state.reflectorWorldPosition)\n    state.virtualCamera.position.copy(state.view)\n    state.virtualCamera.up.set(0, 1, 0)\n    state.virtualCamera.up.applyMatrix4(state.rotationMatrix)\n    state.virtualCamera.up.reflect(state.normal)\n    state.virtualCamera.lookAt(state.target)\n    state.virtualCamera.far = (camera.value as PerspectiveCamera).far\n    state.virtualCamera.updateMatrixWorld()\n    state.virtualCamera.far = (camera.value as PerspectiveCamera).far\n    state.virtualCamera.projectionMatrix.copy((camera.value as PerspectiveCamera).projectionMatrix)\n\n    // NOTE: Update the texture matrix\n    state.textureMatrix.set(0.5, 0.0, 0.0, 0.5, 0.0, 0.5, 0.0, 0.5, 0.0, 0.0, 0.5, 0.5, 0.0, 0.0, 0.0, 1.0)\n    state.textureMatrix.multiply(state.virtualCamera.projectionMatrix)\n    state.textureMatrix.multiply(state.virtualCamera.matrixWorldInverse)\n    state.textureMatrix.multiply(parent.matrixWorld)\n\n    // NOTE: Now update projection matrix with new clip reflectorPlane, implementing code from: http://www.terathon.com/code/oblique.html\n    // Paper explaining this technique: http://www.terathon.com/lengyel/Lengyel-Oblique.pdf\n    state.reflectorPlane.setFromNormalAndCoplanarPoint(state.normal, state.reflectorWorldPosition)\n    state.reflectorPlane.applyMatrix4(state.virtualCamera.matrixWorldInverse)\n    state.clipPlane.set(\n      state.reflectorPlane.normal.x,\n      state.reflectorPlane.normal.y,\n      state.reflectorPlane.normal.z,\n      state.reflectorPlane.constant,\n    )\n    const projectionMatrix = state.virtualCamera.projectionMatrix\n    state.q.x = (Math.sign(state.clipPlane.x) + projectionMatrix.elements[8]) / projectionMatrix.elements[0]\n    state.q.y = (Math.sign(state.clipPlane.y) + projectionMatrix.elements[9]) / projectionMatrix.elements[5]\n    state.q.z = -1.0\n    state.q.w = (1.0 + projectionMatrix.elements[10]) / projectionMatrix.elements[14]\n    // NOTE: Calculate the scaled reflectorPlane vector\n    state.clipPlane.multiplyScalar(2.0 / state.clipPlane.dot(state.q))\n    // NOTE: Replacing the third row of the projection matrix\n    projectionMatrix.elements[2] = state.clipPlane.x\n    projectionMatrix.elements[6] = state.clipPlane.y\n    projectionMatrix.elements[10] = state.clipPlane.z + 1.0\n    projectionMatrix.elements[14] = state.clipPlane.w\n\n    renderer.shadowMap.autoUpdate = false\n    renderer.setRenderTarget(fboSharp)\n    if (!renderer.autoClear) { renderer.clear() }\n\n    renderer.render(toValue(scene), state.virtualCamera)\n    if (renderer instanceof WebGLRenderer) {\n      blurpass.render(renderer, fboSharp, fboBlur)\n    }\n\n    // NOTE: Restore the previous render target and material\n    renderer.xr.enabled = currentXrEnabled\n    renderer.shadowMap.autoUpdate = currentShadowAutoUpdate\n    parent.visible = true\n    renderer.setRenderTarget(null)\n    invalidate()\n  }\n})\ndefineExpose({ instance: materialRef })\n</script>\n\n<template>\n  <TresMeshReflectionMaterial\n    :key=\"`key${hasBlur ? '0' : '1'\n    }${hasDepth ? '0' : '1'\n    }${hasDistortion ? '0' : '1'\n    }${hasRoughness ? '0' : '1'\n    }`\"\n    ref=\"materialRef\"\n    v-bind=\"props\"\n    :texture-matrix=\"state.textureMatrix\"\n    :t-sharp=\"fboSharp?.texture\"\n    :t-depth=\"fboSharp?.depthTexture\"\n    :t-blur=\"fboBlur?.texture\"\n    :defines-USE_BLUR=\"hasBlur ? '' : undefined\"\n    :defines-USE_DEPTH=\"hasDepth ? '' : undefined\"\n    :defines-USE_DISTORTION=\"hasDistortion ? '' : undefined\"\n  />\n</template>\n"
  },
  {
    "path": "src/core/materials/meshReflectionMaterial/material.ts",
    "content": "/*\nInspired by and adapted from MeshReflectorMaterial\nhttps://github.com/pmndrs/drei/blob/master/src/materials/MeshReflectorMaterial.tsx\n\nMIT License\n\nCopyright (c) 2020 react-spring\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n*/\n\nimport { MeshStandardMaterial } from 'three'\nimport type { Matrix4, Texture } from 'three'\n\ninterface UninitializedUniform<Value> { value: Value | null }\n\nexport class MeshReflectionMaterial extends MeshStandardMaterial {\n  private _tDepth: UninitializedUniform<Texture> = { value: null }\n  private _distortionMap: UninitializedUniform<Texture> = { value: null }\n  private _tSharp: UninitializedUniform<Texture> = { value: null }\n  private _tBlur: UninitializedUniform<Texture> = { value: null }\n  private _textureMatrix: UninitializedUniform<Matrix4> = { value: null }\n  private _mix: { value: number } = { value: 0.5 }\n  private _sharpMix: { value: number } = { value: 0.0 }\n  private _blurMixSmooth: { value: number } = { value: 0.0 }\n  private _blurMixRough: { value: number } = { value: 0.0 }\n  private _sharpDepthEdgeMin: { value: number } = { value: 0.9 }\n  private _sharpDepthEdgeMax: { value: number } = { value: 1 }\n  private _sharpDepthScale: { value: number } = { value: 0 }\n  private _sharpDepthBias: { value: number } = { value: 0 }\n  private _distortion: { value: number } = { value: 1 }\n\n  constructor(parameters = {}) {\n    super(parameters)\n    this.setValues(parameters)\n  }\n\n  onBeforeCompile(shader: any) {\n    if (!shader.defines?.USE_UV) {\n      shader.defines.USE_UV = ''\n    }\n    // NOTE: Start #605 fix\n    // Tres lowercases pierced props. As a result, a component\n    // can't set \"defines\", which are written in ALL_CAPS by\n    // convention in the Three.js codebase.\n    //\n    // Issue: https://github.com/Tresjs/tres/issues/605\n    //\n    // A fix has been merged into TresJS v4:\n    // https://github.com/Tresjs/tres/pull/608\n    //\n    // TODO: This code can be removed for TresJS v4.\n    //\n    // Workaround: UPPER_CASE all defines\n    for (const key of Object.keys(shader.defines)) {\n      shader.defines[key.toUpperCase()] = shader.defines[key]\n    }\n    // NOTE: End #605 fix\n\n    shader.uniforms.tSharp = this._tSharp\n    shader.uniforms.tDepth = this._tDepth\n    shader.uniforms.tBlur = this._tBlur\n    shader.uniforms.distortionMap = this._distortionMap\n    shader.uniforms.textureMatrix = this._textureMatrix\n    shader.uniforms.mixMain = this._mix\n\n    shader.uniforms.sharpMix = this._sharpMix\n    shader.uniforms.sharpDepthScale = this._sharpDepthScale\n    shader.uniforms.sharpDepthEdgeMin = this._sharpDepthEdgeMin\n    shader.uniforms.sharpDepthEdgeMax = this._sharpDepthEdgeMax\n    shader.uniforms.sharpDepthBias = this._sharpDepthBias\n\n    shader.uniforms.blurMixSmooth = this._blurMixSmooth\n    shader.uniforms.blurMixRough = this._blurMixRough\n\n    shader.uniforms.distortion = this._distortion\n\n    shader.vertexShader = `\n        uniform mat4 textureMatrix;\n        varying vec4 my_vUv;\n      ${shader.vertexShader}`\n    shader.vertexShader = shader.vertexShader.replace(\n      '#include <project_vertex>',\n      `#include <project_vertex>\n        my_vUv = textureMatrix * vec4( position, 1.0 );\n        gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );`,\n    )\n    shader.fragmentShader = `\n        uniform sampler2D tSharp;\n        uniform sampler2D tBlur;\n        uniform sampler2D tDepth;\n        uniform sampler2D distortionMap;\n        uniform float distortion;\n        uniform float cameraNear;\n        uniform float cameraFar;\n        uniform float mixMain;\n        uniform float sharpMix;\n        uniform float blurMixSmooth;\n        uniform float blurMixRough;\n        uniform float sharpDepthScale;\n        uniform float sharpDepthBias;\n        uniform float sharpDepthEdgeMin;\n        uniform float sharpDepthEdgeMax;\n        varying vec4 my_vUv;\n        ${shader.fragmentShader}`\n    shader.fragmentShader = shader.fragmentShader.replace(\n      '#include <emissivemap_fragment>',\n      `#include <emissivemap_fragment>\n\n      vec4 new_vUv = my_vUv;\n\n      #ifdef USE_DISTORTION\n        float distortionFactor = (texture(distortionMap, vUv).r - 0.5) * distortion;\n        new_vUv.x += distortionFactor;\n        new_vUv.y += distortionFactor;\n      #endif\n\n      #ifdef USE_NORMALMAP\n\n        vec4 normalColor = texture(normalMap, vUv * normalScale);\n        vec3 my_normal = normalize( vec3( normalColor.r * 2.0 - 1.0, normalColor.b,  normalColor.g * 2.0 - 1.0 ) );\n        vec3 coord = new_vUv.xyz / new_vUv.w;\n        vec2 normal_uv = coord.xy + coord.z * my_normal.xz * 0.05;\n\n        vec4 sharp = texture(tSharp, normal_uv);\n\n        #ifdef USE_BLUR\n          vec4 blur = texture(tBlur, normal_uv);\n        #endif\n\n        #ifdef USE_DEPTH\n          vec4 depth = texture(tDepth, normal_uv);\n        #endif\n\n      #else\n\n        vec4 sharp = textureProj(tSharp, new_vUv);\n\n        #ifdef USE_BLUR\n          vec4 blur = textureProj(tBlur, new_vUv);\n        #endif\n\n        #ifdef USE_DEPTH\n          vec4 depth = textureProj(tDepth, new_vUv);\n        #endif\n\n      #endif\n\n      #ifdef USE_DEPTH\n        float depthFactor = smoothstep(\n          1.0 - sharpDepthEdgeMax, 1.0 - sharpDepthEdgeMin,\n          1.0 - (depth.r * depth.a) + sharpDepthBias\n        );\n        depthFactor = clamp(sharpDepthScale * depthFactor, 0.0, 1.0);\n\n        sharp *= depthFactor;\n      #endif\n\n      sharp *= (1.0 - roughnessFactor);\n      `,\n    )\n    shader.fragmentShader = shader.fragmentShader.replace(\n      '#include <opaque_fragment>',\n      `\n\n      #ifdef USE_BLUR\n        outgoingLight += mixMain * (\n          vec3(sharp) * sharpMix\n          + vec3(blur) * (blurMixSmooth * (1.0 - roughnessFactor) + blurMixRough * roughnessFactor)\n        );\n      #else\n        outgoingLight += mixMain * vec3(sharp) * sharpMix;\n      #endif\n\n      #include <opaque_fragment>\n      `,\n    )\n  }\n\n  get tSharp(): Texture | null {\n    return this._tSharp.value\n  }\n\n  set tSharp(v: Texture | null) {\n    this._tSharp.value = v\n  }\n\n  get tDepth(): Texture | null {\n    return this._tDepth.value\n  }\n\n  set tDepth(v: Texture | null) {\n    this._tDepth.value = v\n  }\n\n  get distortionMap(): Texture | null {\n    return this._distortionMap.value\n  }\n\n  set distortionMap(v: Texture | null) {\n    this._distortionMap.value = v\n  }\n\n  get tBlur(): Texture | null {\n    return this._tBlur.value\n  }\n\n  set tBlur(v: Texture | null) {\n    this._tBlur.value = v\n  }\n\n  get textureMatrix(): Matrix4 | null {\n    return this._textureMatrix.value\n  }\n\n  set textureMatrix(v: Matrix4 | null) {\n    this._textureMatrix.value = v\n  }\n\n  get sharpMix(): number {\n    return this._sharpMix.value\n  }\n\n  set sharpMix(v: number) {\n    this._sharpMix.value = v\n  }\n\n  get blurMixSmooth(): number {\n    return this._blurMixSmooth.value\n  }\n\n  set blurMixSmooth(v: number) {\n    this._blurMixSmooth.value = v\n  }\n\n  get blurMixRough(): number {\n    return this._blurMixRough.value\n  }\n\n  set blurMixRough(v: number) {\n    this._blurMixRough.value = v\n  }\n\n  get mix(): number {\n    return this._mix.value\n  }\n\n  set mix(v: number) {\n    this._mix.value = v\n  }\n\n  get sharpDepthScale(): number {\n    return this._sharpDepthScale.value\n  }\n\n  set sharpDepthScale(v: number) {\n    this._sharpDepthScale.value = v\n  }\n\n  get sharpDepthBias(): number {\n    return this._sharpDepthBias.value\n  }\n\n  set sharpDepthBias(v: number) {\n    this._sharpDepthBias.value = v\n  }\n\n  get sharpDepthEdgeMin(): number {\n    return this._sharpDepthEdgeMin.value\n  }\n\n  set sharpDepthEdgeMin(v: number) {\n    this._sharpDepthEdgeMin.value = v\n  }\n\n  get sharpDepthEdgeMax(): number {\n    return this._sharpDepthEdgeMax.value\n  }\n\n  set sharpDepthEdgeMax(v: number) {\n    this._sharpDepthEdgeMax.value = v\n  }\n\n  get distortion(): number {\n    return this._distortion.value\n  }\n\n  set distortion(v: number) {\n    this._distortion.value = v\n  }\n}\n"
  },
  {
    "path": "src/core/materials/meshWobbleMaterial/index.vue",
    "content": "<script setup lang=\"ts\">\nimport { useLoop, useTres } from '@tresjs/core'\nimport { shallowRef, watch } from 'vue'\n\nimport { WobbleMaterialImpl as MeshWobbleMaterial } from './material'\n\nconst props = withDefaults(\n  defineProps<{\n    speed?: number\n    factor?: number\n  }>(),\n  {\n    speed: 1,\n    factor: 1,\n  },\n)\n\nconst materialRef = shallowRef()\n\nconst { extend, invalidate } = useTres()\n\nextend({ MeshWobbleMaterial })\n\nwatch(props, () => {\n  invalidate()\n})\n\nconst { onBeforeRender } = useLoop()\n\nonBeforeRender(({ elapsed }) => {\n  if (materialRef.value) {\n    materialRef.value.time = elapsed * props?.speed\n    invalidate()\n  }\n})\n\ndefineExpose({ instance: materialRef })\n</script>\n\n<template>\n  <TresMeshWobbleMaterial\n    ref=\"materialRef\"\n    :factor=\"factor\"\n    v-bind=\"$attrs\"\n  />\n</template>\n"
  },
  {
    "path": "src/core/materials/meshWobbleMaterial/material.ts",
    "content": "import { MeshStandardMaterial } from 'three'\nimport type { MeshStandardMaterialParameters } from 'three'\n\n// Borrowed from @pmdrs drei implementation https://github.com/pmndrs/drei/blob/master/src/core/MeshWobbleMaterial.tsx\ninterface Uniform<T> {\n  value: T\n}\n\nexport class WobbleMaterialImpl extends MeshStandardMaterial {\n  _time: Uniform<number>\n  _factor: Uniform<number>\n\n  constructor(parameters: MeshStandardMaterialParameters = {}) {\n    super(parameters)\n    this.setValues(parameters)\n    this._time = { value: 0 }\n    this._factor = { value: 1 }\n  }\n\n  onBeforeCompile(shader: { uniforms: { time?: Uniform<number>, factor?: Uniform<number> }, vertexShader: string }) {\n    if (!shader.uniforms) { shader.uniforms = {} }\n    shader.uniforms.time = this._time\n    shader.uniforms.factor = this._factor\n\n    shader.vertexShader = `\n        uniform float time;\n        uniform float factor;\n        ${shader.vertexShader}\n      `\n    shader.vertexShader = shader.vertexShader.replace(\n      '#include <begin_vertex>',\n      `float theta = sin( time + position.y ) / 2.0 * factor;\n          float c = cos( theta );\n          float s = sin( theta );\n          mat3 m = mat3( c, 0, s, 0, 1, 0, -s, 0, c );\n          vec3 transformed = vec3( position ) * m;\n          vNormal = vNormal * m;`,\n    )\n  }\n\n  get time() {\n    return this._time.value\n  }\n\n  set time(v) {\n    this._time.value = v\n  }\n\n  get factor() {\n    return this._factor.value\n  }\n\n  set factor(v) {\n    this._factor.value = v\n  }\n}\n"
  },
  {
    "path": "src/core/materials/pointMaterial/component.vue",
    "content": "<script setup lang=\"ts\">\nimport { onUnmounted, shallowRef, watch } from 'vue'\nimport { extend } from '@tresjs/core'\nimport { PointMaterial as PointMaterialImpl } from './material'\n\nconst props = defineProps<{\n  sizeAttenuation?: boolean\n}>()\n\nextend({ PointMaterial: PointMaterialImpl })\n\nconst materialRef = shallowRef(new PointMaterialImpl({ sizeAttenuation: props.sizeAttenuation }))\n\nwatch(() => props.sizeAttenuation, () => {\n  // NOTE: sizeAttenuation does not appear to work\n  // reactively without recreating the material.\n  if (materialRef.value) {\n    materialRef.value.dispose()\n  }\n  materialRef.value = new PointMaterialImpl({ sizeAttenuation: props.sizeAttenuation })\n})\n\nonUnmounted(() => {\n  if (materialRef.value && materialRef.value.dispose) {\n    materialRef.value.dispose()\n  }\n})\n\ndefineExpose({ instance: materialRef })\n</script>\n\n<template>\n  <primitive :object=\"materialRef\" />\n</template>\n"
  },
  {
    "path": "src/core/materials/pointMaterial/material.ts",
    "content": "import { PointsMaterial as PointsMaterialImpl, type PointsMaterialParameters } from 'three'\n\n// NOTE: Source\n// https://github.com/pmndrs/drei/blob/master/src/core/PointMaterial.tsx\n\nconst opaque_fragment = 'opaque_fragment'\n\nexport class PointMaterial extends PointsMaterialImpl {\n  constructor(props: PointsMaterialParameters) {\n    super(props)\n    this.onBeforeCompile = (shader, renderer) => {\n      const { isWebGL2 } = renderer.capabilities\n      shader.fragmentShader = shader.fragmentShader.replace(\n        `#include <${opaque_fragment}>`,\n        `\n        ${\n          !isWebGL2\n            ? `#extension GL_OES_standard_derivatives : enable\\n#include <${opaque_fragment}>`\n            : `#include <${opaque_fragment}>`\n        }\n      vec2 cxy = 2.0 * gl_PointCoord - 1.0;\n      float r = dot(cxy, cxy);\n      float delta = fwidth(r);     \n      float mask = 1.0 - smoothstep(1.0 - delta, 1.0 + delta, r);\n      gl_FragColor = vec4(gl_FragColor.rgb, mask * gl_FragColor.a );\n      #include <tonemapping_fragment>\n      #include <colorspace_fragment>\n      `,\n      )\n    }\n  }\n}\n"
  },
  {
    "path": "src/core/misc/BakeShadows.ts",
    "content": "import { useTres } from '@tresjs/core'\nimport { WebGLRenderer } from 'three'\nimport { defineComponent, watchEffect } from 'vue'\n\nexport const BakeShadows = defineComponent({\n  name: 'BakeShadows',\n\n  setup() {\n    const { renderer } = useTres()\n\n    watchEffect(() => {\n      if (renderer instanceof WebGLRenderer) {\n        renderer.shadowMap.autoUpdate = false\n        renderer.shadowMap.needsUpdate = true\n      }\n    })\n  },\n})\n"
  },
  {
    "path": "src/core/misc/LOD.vue",
    "content": "<script setup lang=\"ts\">\nimport type { Object3D, Object3DEventMap } from 'three'\nimport { LOD } from 'three'\nimport { isReactive, onMounted, shallowRef, watch } from 'vue'\n\ninterface LODProps {\n  /**\n   * The distances at which to display each level of detail.\n   * There should be one `levels` value for each `LOD` child.\n   */\n  levels: number[]\n  /**\n  * Threshold used to avoid flickering at LOD boundaries, as a fraction of distance\n  * @default 0.0\n  */\n  hysteresis?: number\n}\n\nconst props = withDefaults(\n  defineProps<LODProps>(),\n  {\n    hysteresis: 0.0,\n  },\n)\n\nconst lodRef = shallowRef(new LOD())\n\nfunction onChange() {\n  // NOTE: Check validity of `levels`.\n  // It should exist. It should be an array. Every value should be a number.\n  const distances = (props.levels && props.levels.length && props.levels.every(n => typeof n === 'number')) ? [...props.levels] : [1000]\n\n  // NOTE: Add `levels` values if there fewer `levels` values than `children`.\n  while (distances.length < lodRef.value.children.length) {\n    distances.push(Math.abs(distances[distances.length - 1]) * 2)\n  }\n\n  // NOTE: Levels can be in any order, but the THREE implementation doesn't work\n  // work properly unless the levels are pushed in ascending order of `distance`.\n  // So, construct ascending order of `distance`.\n  const levels = [] as { distance: number, hysteresis: number, object: Object3D<Object3DEventMap> }[]\n  for (let i = 0; i < lodRef.value.children.length; i++) {\n    const hysteresis = props.hysteresis\n    const distance = distances[i]\n    const object = lodRef.value.children[i] as Object3D<Object3DEventMap>\n    levels.push({ hysteresis, distance, object })\n  }\n  levels.sort((a, b) => a.distance - b.distance)\n\n  // NOTE: Clear the current LOD levels.\n  lodRef.value.levels.length = 0\n\n  // NOTE: Push levels in ascending order of `distance`.\n  levels.forEach(level => lodRef.value.levels.push(level))\n}\n\nif (isReactive(props.levels)) {\n  watch(() => props.levels, onChange)\n}\n\nif (isReactive(props.hysteresis)) {\n  watch(() => props.hysteresis, onChange)\n}\n\nonMounted(onChange)\n\ndefineExpose({\n  instance: lodRef,\n})\n</script>\n\n<template>\n  <TresLOD ref=\"lodRef\">\n    <slot></slot>\n  </TresLOD>\n</template>\n"
  },
  {
    "path": "src/core/misc/Stats.ts",
    "content": "import { useLoop } from '@tresjs/core'\nimport StatsImpl from 'stats.js'\nimport { defineComponent, onUnmounted } from 'vue'\n\nexport const Stats = defineComponent({\n  name: 'Stats',\n  props: {\n    showPanel: {\n      type: Number,\n      default: 0,\n    },\n  },\n\n  setup(props, { expose }) {\n    const stats = new StatsImpl()\n\n    expose({ instance: stats })\n\n    const node = document.body\n    stats.showPanel(props.showPanel || 0)\n    node?.appendChild(stats.dom)\n\n    const { onBeforeRender, onRender } = useLoop()\n    onBeforeRender(() => stats.begin(), Number.NEGATIVE_INFINITY)\n    onRender(() => stats.end(), Number.POSITIVE_INFINITY)\n\n    onUnmounted(() => {\n      node?.removeChild(stats.dom)\n    })\n  },\n})\n"
  },
  {
    "path": "src/core/misc/StatsGl.ts",
    "content": "import { useLoop, useTresContext } from '@tresjs/core'\nimport StatsGlImpl from 'stats-gl'\nimport { defineComponent, onUnmounted } from 'vue'\n\nexport interface StatsGlProps {\n  /*\n   * How often to log performance data, in logs per second.\n   *\n   * @default 20\n   * @type {number}\n   * @memberof StatsGlProps\n   */\n  logsPerSecond?: number\n\n  /*\n   * Number of recent log samples to keep for computing averages.\n   *\n   * @default 100\n   * @type {number}\n   * @memberof StatsGlProps\n   */\n  samplesLog?: number\n\n  /*\n   * Number of recent graph samples to keep for computing averages.\n   *\n   * @default 10\n   * @type {number}\n   * @memberof StatsGlProps\n   */\n  samplesGraph?: number\n\n  /*\n   * Precision of the data, in number of decimal places (only affects CPU and GPU).\n   *\n   * @default 2\n   * @type {number}\n   * @memberof StatsGlProps\n   */\n  precision?: number\n\n  /*\n   * Display the canvases on the X axis, set to align on vertical axis.\n   *\n   * @default true\n   * @type {boolean}\n   * @memberof StatsGlProps\n   */\n  horizontal?: boolean\n\n  /*\n   * A boolean value to control the minimalistic mode of the panel display. If set to true, a simple click on the panel will switch between different metrics.\n   *\n   * @default false\n   * @type {boolean}\n   * @memberof StatsGlProps\n   */\n  minimal?: boolean\n\n  /*\n   * Sets the initial panel to display - 0 for FPS, 1 for CPU, and 2 for GPU (if supported).\n   *\n   * @default 0\n   * @type {number}\n   * @memberof StatsGlProps\n   */\n  mode?: number\n}\n\nexport const StatsGl = defineComponent<StatsGlProps>({\n  name: 'StatsGl',\n  props: [\n    'logsPerSecond',\n    'samplesLog',\n    'samplesGraph',\n    'precision',\n    'horizontal',\n    'minimal',\n    'mode',\n  ] as unknown as undefined,\n\n  setup(props, { expose }) {\n    const statsGl = new StatsGlImpl({\n      logsPerSecond: props.logsPerSecond,\n      samplesLog: props.samplesLog,\n      samplesGraph: props.samplesGraph,\n      precision: props.precision,\n      horizontal: props.horizontal,\n      minimal: props.minimal,\n      mode: props.mode,\n    })\n\n    expose({ instance: statsGl })\n\n    const node = document.body\n    // @ts-expect-error - container is not typed\n    const statContainer = statsGl.container\n\n    node?.appendChild(statContainer)\n\n    const { renderer } = useTresContext()\n\n    const { onRender } = useLoop()\n\n    statsGl.init(renderer.instance)\n\n    onRender(() => statsGl.update(), Number.POSITIVE_INFINITY)\n\n    onUnmounted(() => {\n      node?.removeChild(statContainer)\n    })\n  },\n\n})\n"
  },
  {
    "path": "src/core/misc/html/HTML.vue",
    "content": "<script setup lang=\"ts\">\nimport { useLoop, useTresContext } from '@tresjs/core'\nimport type {\n  OrthographicCamera,\n} from 'three'\nimport {\n  DoubleSide,\n  PlaneGeometry,\n  Raycaster,\n  ShaderMaterial,\n  Vector3,\n} from 'three'\nimport { computed, createVNode, isRef, onUnmounted, ref, render, toRefs, useAttrs, watch, watchEffect } from 'vue'\nimport type { TresCamera, TresObject, TresObject3D } from '@tresjs/core'\nimport type { Mutable } from '@vueuse/core'\n\nimport type { VNode } from 'vue'\nimport fragmentShader from './shaders/fragment.glsl'\nimport vertexShader from './shaders/vertex.glsl'\nimport {\n  calculatePosition,\n  epsilon,\n  getCameraCSSMatrix,\n  getObjectCSSMatrix,\n  isObjectBehindCamera,\n  isObjectVisible,\n  objectScale,\n  objectZIndex,\n} from './utils'\n\nexport interface HTMLProps {\n  geometry?: any\n  material?: any\n  as?: string\n  transform?: boolean\n  portal?: Mutable<HTMLElement>\n  wrapperClass?: string\n  eps?: number\n  distanceFactor?: number\n  fullscreen?: boolean\n  center?: boolean\n  pointerEvents?: PointerEventsProperties\n  sprite?: boolean\n  zIndexRange?: Array<number>\n\n  // Occlusion based off work by Jerome Etienne and James Baicoianu\n  // https://www.youtube.com/watch?v=ScZcUEDGjJI\n  // as well as Joe Pea in CodePen: https://codepen.io/trusktr/pen/RjzKJx\n  occlude?: TresObject3D | null | (TresObject3D | null)[] | boolean | 'raycast' | 'blending'\n}\n\nconst props = withDefaults(defineProps<HTMLProps>(), {\n  geometry: new PlaneGeometry(),\n  zIndexRange: () => [16777271, 0],\n  as: 'div',\n  transform: false,\n  eps: 0.0001,\n  pointerEvents: 'auto',\n  sprite: false,\n})\n\nconst emits = defineEmits(['onOcclude'])\n\nconst slots = defineSlots()\n\ntype PointerEventsProperties =\n  | 'auto'\n  | 'none'\n  | 'visiblePainted'\n  | 'visibleFill'\n  | 'visibleStroke'\n  | 'visible'\n  | 'painted'\n  | 'fill'\n  | 'stroke'\n  | 'all'\n  | 'inherit'\n\nconst attrs = useAttrs()\n\nconst groupRef = ref<TresObject3D>()\nconst meshRef = ref<TresObject3D>()\n\nconst {\n  geometry,\n  material,\n  as,\n  transform,\n  portal,\n  wrapperClass,\n  eps,\n  distanceFactor,\n  fullscreen,\n  center,\n  pointerEvents,\n  sprite,\n  occlude,\n  zIndexRange,\n} = toRefs(props)\n\nconst { renderer, scene, camera, sizes } = useTresContext()\n\nconst el = computed(() => document.createElement(as.value))\n\nconst previousPosition = ref([0, 0, 0])\nconst previousZoom = ref(0)\nconst vnode = ref<VNode>()\nconst raycaster = ref<Raycaster>(new Raycaster())\n\nconst styles = computed(() => {\n  if (transform.value) {\n    return {\n      position: 'absolute',\n      top: 0,\n      left: 0,\n      width: `${sizes.width.value}px`,\n      height: `${sizes.height.value}px`,\n      transformStyle: 'preserve-3d',\n      pointerEvents: 'none',\n      zIndex: 2,\n    }\n  }\n  else {\n    return {\n      position: 'absolute',\n      transform: center.value ? 'translate3d(-50%,-50%,0)' : 'none',\n      ...(fullscreen.value && {\n        top: -(sizes.height.value) / 2,\n        left: -(sizes.width.value) / 2,\n        width: `${sizes.width.value}px`,\n        height: `${sizes.height.value}px`,\n      }),\n      zIndex: 2,\n      ...Object.assign({}, attrs.style),\n    }\n  }\n})\n\nconst transformInnerStyles = computed(() => ({\n  position: 'absolute',\n  pointerEvents: pointerEvents.value,\n}))\n\n// Occlussion\nconst occlusionMeshRef = ref<TresObject>(null!)\nconst isMeshSizeSet = ref(false)\n\nconst isRayCastOcclusion = computed(\n  () =>\n    (occlude?.value && occlude?.value !== 'blending')\n    || (Array.isArray(occlude?.value) && occlude?.value.length && isRef(occlude.value[0])),\n)\n\nwatch(\n  () => occlude,\n  ({ value }) => {\n    if (value === 'blending') {\n      el.value.style.zIndex = `${Math.floor(zIndexRange.value[0] / 2)}`\n      el.value.style.position = 'absolute'\n      el.value.style.pointerEvents = 'none'\n    }\n    else {\n      el.value.style.zIndex = null!\n      el.value.style.position = null!\n      el.value.style.pointerEvents = null!\n    }\n  },\n)\n\nwatch(\n  () => [groupRef.value, renderer.instance, sizes.width.value, sizes.height.value, slots.default?.()],\n  ([group, renderer]): void => {\n    if (group && renderer) {\n      const target = portal?.value || renderer.domElement\n      scene.value?.updateMatrixWorld()\n\n      if (transform.value) {\n        el.value.style.cssText = 'position:absolute;top:0;left:0;pointer-events:none;overflow:hidden;'\n      }\n      else {\n        const vector = calculatePosition(group, camera.activeCamera.value as TresCamera, {\n          width: sizes.width.value,\n          height: sizes.height.value,\n        })\n        el.value.style.cssText\n        = `position:absolute;top:0;left:0;transform:translate3d(${vector[0]}px,${vector[1]}px,0);transform-origin:0 0;`\n      }\n\n      if (target && !el.value.parentNode) {\n        target.parentNode?.appendChild(el.value)\n      }\n\n      if (transform.value) {\n        vnode.value = createVNode('div', { id: 'outer', style: styles.value }, [\n          createVNode('div', { id: 'inner', style: transformInnerStyles.value }, [\n            createVNode('div', {\n              key: meshRef.value?.uuid,\n              id: scene?.value.uuid,\n              class: attrs.class,\n              style: attrs.style,\n            }, slots.default?.()),\n          ]),\n        ])\n      }\n      else {\n        vnode.value = createVNode('div', {\n          key: meshRef.value?.uuid,\n          id: scene?.value.uuid,\n          style: styles.value,\n        }, slots.default?.())\n      }\n      render(vnode.value, el.value)\n    }\n  },\n)\n\nwatchEffect(() => {\n  if (wrapperClass?.value) {\n    el.value.className = wrapperClass.value\n  }\n})\n\nconst visible = ref(true)\n\nconst { onBeforeRender } = useLoop()\n\nonBeforeRender(() => {\n  // TODO: comment this until invalidate is back in the loop callback on v5\n  // invalidate()\n\n  if (groupRef.value && camera.activeCamera.value && renderer.instance) {\n    camera.activeCamera.value?.updateMatrixWorld()\n    groupRef.value.updateWorldMatrix(true, false)\n\n    const vector = transform.value\n      ? previousPosition.value\n      : calculatePosition(groupRef.value, camera.activeCamera.value as TresCamera, {\n          width: sizes.width.value || 0,\n          height: sizes.height.value || 0,\n        })\n\n    if (\n      transform.value\n      || Math.abs(previousZoom.value - (camera.activeCamera.value as TresCamera).zoom) > eps.value\n      || Math.abs(previousPosition.value[0] - vector[0]) > eps.value\n      || Math.abs(previousPosition.value[1] - vector[1]) > eps.value\n      || Math.abs(previousPosition.value[2] - vector[2]) > eps.value\n    ) {\n      const isBehindCamera = isObjectBehindCamera(groupRef.value, camera.activeCamera.value as TresCamera)\n      let raytraceTarget: null | undefined | boolean | TresObject3D[] = false\n\n      if (isRayCastOcclusion.value) {\n        if (Array.isArray(occlude?.value)) {\n          raytraceTarget = occlude?.value as unknown as TresObject3D[]\n        }\n        else if (occlude?.value !== 'blending') {\n          raytraceTarget = [scene.value as unknown as TresObject3D]\n        }\n      }\n\n      const previouslyVisible = visible.value\n\n      if (raytraceTarget) {\n        const isVisible = isObjectVisible(\n          groupRef.value,\n          camera.activeCamera.value as TresCamera,\n          raycaster.value,\n          raytraceTarget as TresObject3D[],\n        )\n        visible.value = isVisible && !isBehindCamera\n      }\n      else {\n        visible.value = !isBehindCamera\n      }\n\n      if (previouslyVisible !== visible.value) {\n        emits('onOcclude', !visible.value)\n        el.value.style.display = visible.value ? 'block' : 'none'\n      }\n\n      const halfRange = Math.floor(zIndexRange.value[0] / 2)\n      const zRange = occlude?.value\n        ? isRayCastOcclusion.value //\n          ? [zIndexRange.value[0], halfRange]\n          : [halfRange - 1, 0]\n        : zIndexRange.value\n\n      el.value.style.zIndex = `${objectZIndex(groupRef.value, camera.activeCamera.value as TresCamera, zRange)}`\n      if (transform.value) {\n        const [widthHalf, heightHalf] = [\n          (sizes.width.value) / 2,\n          (sizes.height.value) / 2,\n        ]\n        const fov = camera.activeCamera.value.projectionMatrix.elements[5] * heightHalf\n        const { isOrthographicCamera, top, left, bottom, right } = camera.activeCamera.value as OrthographicCamera\n        const cameraMatrix = getCameraCSSMatrix(camera.activeCamera.value.matrixWorldInverse)\n        const cameraTransform = isOrthographicCamera\n          ? `scale(${fov})translate(${epsilon(-(right + left) / 2)}px,${epsilon((top + bottom) / 2)}px)`\n          : `translateZ(${fov}px)`\n        let matrix = groupRef.value.matrixWorld\n        if (sprite.value) {\n          matrix = camera.activeCamera.value.matrixWorldInverse.clone().transpose().copyPosition(matrix).scale(groupRef.value.scale)\n          matrix.elements[3] = matrix.elements[7] = matrix.elements[11] = 0\n          matrix.elements[15] = 1\n        }\n        el.value.style.width = `${sizes.width.value}px`\n        el.value.style.height = `${sizes.height.value}px`\n        el.value.style.perspective = isOrthographicCamera ? '' : `${fov}px`\n\n        if (vnode.value?.el && vnode.value?.children && Array.isArray(vnode.value.children)) {\n          vnode.value.el.style.transform = `${cameraTransform}${cameraMatrix}translate(${widthHalf}px,${heightHalf}px)`\n\n          const firstChild = vnode.value.children[0] as VNode\n          if (firstChild && firstChild.el) {\n            firstChild.el.style.transform = getObjectCSSMatrix(\n              matrix,\n              1 / ((distanceFactor?.value || 10) / 400),\n            )\n          }\n        }\n      }\n      else {\n        const scale\n          = distanceFactor?.value === undefined\n            ? 1\n            : objectScale(groupRef.value, camera.activeCamera.value as TresCamera) * distanceFactor?.value\n        el.value.style.transform = `translate3d(${vector[0]}px,${vector[1]}px,0) scale(${scale})`\n      }\n    }\n\n    previousPosition.value = vector\n    previousZoom.value = (camera.activeCamera.value as TresCamera).zoom\n  }\n\n  if (!isRayCastOcclusion.value && meshRef.value && !isMeshSizeSet.value) {\n    if (transform.value) {\n      if (vnode.value?.el && vnode.value?.children) {\n        const el = (vnode.value?.children as unknown as Array<HTMLElement>)[0]\n\n        if (el?.clientWidth && el?.clientHeight) {\n          const { isOrthographicCamera } = camera.activeCamera.value as OrthographicCamera\n\n          if (isOrthographicCamera || geometry) {\n            if (attrs.scale) {\n              if (!Array.isArray(attrs.scale)) {\n                meshRef.value.scale.setScalar(1 / (attrs.scale as number))\n              }\n              else if (attrs.scale instanceof Vector3) {\n                meshRef.value.scale.copy(attrs.scale.clone().divideScalar(1))\n              }\n              else {\n                meshRef.value.scale.set(1 / attrs.scale[0], 1 / attrs.scale[1], 1 / attrs.scale[2])\n              }\n            }\n          }\n          else {\n            const ratio = (distanceFactor?.value || 10) / 400\n            const w = el.clientWidth * ratio\n            const h = el.clientHeight * ratio\n\n            meshRef.value.scale.set(w, h, 1)\n          }\n\n          isMeshSizeSet.value = true\n        }\n      }\n    }\n    else {\n      const ele = el.value.children[0]\n\n      if (ele?.clientWidth && ele?.clientHeight) {\n        const ratio = 1 / 1\n        const w = ele.clientWidth * ratio\n        const h = ele.clientHeight * ratio\n\n        meshRef.value.scale.set(w, h, 1)\n\n        isMeshSizeSet.value = true\n      }\n\n      occlusionMeshRef.value.lookAt(camera.activeCamera.value?.position)\n    }\n  }\n})\n\n// TODO: Check ShaderMaterial disposal\nconst shaders = computed(() => ({\n  vertexShader: transform.value\n    ? undefined\n    : vertexShader,\n  fragmentShader,\n}))\n\nconst shaderMaterial = computed(() => {\n  const shader = shaders.value\n  return (\n    material.value\n    || new ShaderMaterial({\n      vertexShader: shader.vertexShader as string,\n      fragmentShader: shader.fragmentShader as string,\n      side: DoubleSide,\n    })\n  )\n})\n\nonUnmounted(() => {\n  if (shaderMaterial.value) {\n    shaderMaterial.value.dispose()\n  }\n  el.value.remove()\n})\n\ndefineExpose({ instance: groupRef })\n</script>\n\n<template>\n  <TresGroup ref=\"groupRef\">\n    <template v-if=\"occlude && !isRayCastOcclusion\">\n      <TresMesh\n        ref=\"meshRef\"\n        :geometry=\"geometry\"\n        :material=\"shaderMaterial\"\n      />\n    </template>\n  </TresGroup>\n</template>\n"
  },
  {
    "path": "src/core/misc/html/shaders/fragment.glsl",
    "content": "void main() {\n  gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);\n}"
  },
  {
    "path": "src/core/misc/html/shaders/vertex.glsl",
    "content": "#include <common>\n\nvoid main() {\n  vec2 center = vec2(0., 1.);\n  float rotation = 0.0;\n\n  // This is somewhat arbitrary, but it seems to work well\n  // Need to figure out how to derive this dynamically if it even matters\n  float size = 0.03;\n\n  vec4 mvPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );\n  vec2 scale;\n  scale.x = length( vec3( modelMatrix[ 0 ].x, modelMatrix[ 0 ].y, modelMatrix[ 0 ].z ) );\n  scale.y = length( vec3( modelMatrix[ 1 ].x, modelMatrix[ 1 ].y, modelMatrix[ 1 ].z ) );\n\n  bool isPerspective = isPerspectiveMatrix( projectionMatrix );\n  if ( isPerspective ) scale *= - mvPosition.z;\n\n  vec2 alignedPosition = ( position.xy - ( center - vec2( 0.5 ) ) ) * scale * size;\n  vec2 rotatedPosition;\n  rotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;\n  rotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;\n  mvPosition.xy += rotatedPosition;\n\n  gl_Position = projectionMatrix * mvPosition;\n}"
  },
  {
    "path": "src/core/misc/html/utils.ts",
    "content": "import { OrthographicCamera, PerspectiveCamera, Vector2, Vector3 } from 'three'\nimport type { TresCamera, TresObject3D } from '@tresjs/core'\nimport type { Matrix4, Raycaster } from 'three'\n\nexport const v1 = new Vector3(0, 0, 0)\nexport const v2 = new Vector3(0, 0, 0)\nexport const v3 = new Vector3(0, 0, 0)\n\nexport function calculatePosition(instance: TresObject3D, camera: TresCamera, size: { width: number, height: number }) {\n  const objectPos = v1.setFromMatrixPosition(instance.matrixWorld)\n  objectPos.project(camera)\n  const widthHalf = size.width / 2\n  const heightHalf = size.height / 2\n  return [\n    (Number.isNaN(objectPos.x) ? 0 : objectPos.x) * widthHalf + widthHalf,\n    -(objectPos.y * heightHalf) + heightHalf,\n    objectPos.z,\n  ]\n}\n\nexport function isObjectBehindCamera(el: TresObject3D, camera: TresCamera) {\n  const objectPos = v1.setFromMatrixPosition(el.matrixWorld)\n  const cameraPos = v2.setFromMatrixPosition(camera.matrixWorld)\n  const deltaCamObj = objectPos.sub(cameraPos)\n  const camDir = camera.getWorldDirection(v3)\n  return deltaCamObj.angleTo(camDir) > Math.PI / 2\n}\n\nexport function isObjectVisible(el: TresObject3D, camera: TresCamera, raycaster: Raycaster, occlude: any) {\n  const elPos = v1.setFromMatrixPosition(el.matrixWorld)\n  const screenPos = elPos.clone()\n  screenPos.project(camera)\n  raycaster.setFromCamera(new Vector2(screenPos.x, screenPos.y), camera)\n  const intersects = raycaster.intersectObjects(occlude, true)\n\n  if (intersects.length > 0) {\n    const intersectionDistance = intersects[0].distance\n    const pointDistance = elPos.distanceTo(raycaster.ray.origin)\n\n    return pointDistance < intersectionDistance\n  }\n  return true\n}\n\nexport function objectScale(el: TresObject3D, camera: TresCamera) {\n  if (camera instanceof OrthographicCamera) {\n    return camera.zoom\n  }\n  else if (camera instanceof PerspectiveCamera) {\n    const objectPos = v1.setFromMatrixPosition(el.matrixWorld)\n    const cameraPos = v2.setFromMatrixPosition(camera.matrixWorld)\n    const vFOV = (camera.fov * Math.PI) / 180\n    const dist = objectPos.distanceTo(cameraPos)\n    const scaleFOV = 2 * Math.tan(vFOV / 2) * dist\n    return 1 / scaleFOV\n  }\n  else {\n    return 1\n  }\n}\n\nexport function objectZIndex(el: TresObject3D, camera: TresCamera, zIndexRange: Array<number>) {\n  if (camera instanceof PerspectiveCamera || camera instanceof OrthographicCamera) {\n    const objectPos = v1.setFromMatrixPosition(el.matrixWorld)\n    const cameraPos = v2.setFromMatrixPosition(camera.matrixWorld)\n    const dist = objectPos.distanceTo(cameraPos)\n    const A = (zIndexRange[1] - zIndexRange[0]) / (camera.far - camera.near)\n    const B = zIndexRange[1] - A * camera.far\n    return Math.round(A * dist + B)\n  }\n  return undefined\n}\n\nexport const epsilon = (value: number) => (Math.abs(value) < 1e-10 ? 0 : value)\n\nexport function getCSSMatrix(matrix: Matrix4, multipliers: number[], prepend = '') {\n  let matrix3d = 'matrix3d('\n  for (let i = 0; i !== 16; i++) {\n    matrix3d += epsilon(multipliers[i] * matrix.elements[i]) + (i !== 15 ? ',' : ')')\n  }\n  return prepend + matrix3d\n}\n\nexport const getCameraCSSMatrix\n  = ((multipliers: number[]) =>\n    (matrix: Matrix4) => getCSSMatrix(matrix, multipliers))([1, -1, 1, 1, 1, -1, 1, 1, 1, -1, 1, 1, 1, -1, 1, 1])\n\nexport const getObjectCSSMatrix\n  = ((scaleMultipliers: (n: number) => number[]) =>\n    (matrix: Matrix4, factor: number) =>\n      getCSSMatrix(matrix, scaleMultipliers(factor), 'translate(-50%,-50%)'))((f: number) =>\n    [1 / f, 1 / f, 1 / f, 1, -1 / f, -1 / f, -1 / f, -1, 1 / f, 1 / f, 1 / f, 1, 1, 1, 1, 1])\n"
  },
  {
    "path": "src/core/misc/index.ts",
    "content": "import { BakeShadows } from './BakeShadows'\nimport LOD from './LOD.vue'\nimport Html from './html/HTML.vue'\nimport { Stats } from './Stats'\nimport { StatsGl } from './StatsGl'\nimport { useGLTFExporter } from './useGLTFExporter'\nimport { useIntersect } from './useIntersect'\n\nexport {\n  BakeShadows,\n  Html,\n  LOD,\n  Stats,\n  StatsGl,\n  useGLTFExporter,\n  useIntersect,\n}\n"
  },
  {
    "path": "src/core/misc/useGLTFExporter.ts",
    "content": "import { logError } from '@tresjs/core'\nimport { GLTFExporter } from 'three-stdlib'\nimport type { AnimationClip, Object3D } from 'three'\n\ninterface gltfExporterOptions {\n  fileName?: string\n  trs?: boolean\n  onlyVisible?: boolean\n  binary?: boolean\n  maxTextureSize?: number\n  animations?: AnimationClip[]\n  includeCustomExtensions?: boolean\n}\n\nexport async function useGLTFExporter(\n  object3D: Object3D | Object3D[],\n  options?: gltfExporterOptions,\n) {\n  const exporter = new GLTFExporter()\n  const name = options?.fileName || 'scene'\n\n  exporter.parse(\n    object3D,\n    (gltf) => {\n      if (gltf instanceof ArrayBuffer) {\n        saveArrayBuffer(gltf, `${name}.glb`)\n      }\n      else {\n        const output = JSON.stringify(gltf, null, 2)\n        saveString(output, `${name}.gltf`)\n      }\n    },\n    (error: any) => {\n      logError('An error happened while exporting the GLTF', error)\n    },\n    options,\n  )\n}\n\nfunction saveString(text: string, filename: string) {\n  save(new Blob([text], { type: 'text/plain' }), filename)\n}\n\nfunction saveArrayBuffer(buffer: any, filename: string) {\n  save(new Blob([buffer], { type: 'application/octet-stream' }), filename)\n}\n\nfunction save(blob: Blob, filename: string) {\n  const link = document.createElement('a')\n  link.style.display = 'none'\n  document.body.appendChild(link)\n  link.href = URL.createObjectURL(blob)\n  link.download = filename\n  link.click()\n  link.remove()\n}\n"
  },
  {
    "path": "src/core/misc/useIntersect.ts",
    "content": "import { useLoop } from '@tresjs/core'\nimport type { Object3D } from 'three'\nimport type { Ref } from 'vue'\nimport { shallowRef, unref, watch } from 'vue'\n\n// NOTE: Inspiration\n// https://github.com/pmndrs/drei/blob/master/src/core/useIntersect.tsx\n\ntype UseIntersectCallback = (isIntersected: boolean) => void\n\n// NOTE: As of this writing, Cientos components\n// use `defineExpose` in this form:\n// defineExpose({ instance: THE_COMPONENT })\n//\n// This means they have to be accessed like\n// `obj.instance`, and not merely `obj`\ninterface CientosExposed { instance: Object3D }\ntype ObjOrCientosExposed = Object3D | CientosExposed\nfunction normalizeCientosInstance(obj: ObjOrCientosExposed) {\n  if ('onBeforeRender' in obj && 'onAfterRender' in obj) { return obj }\n  return obj.instance\n}\n\nexport function useIntersect<T extends Object3D>(onChange: Ref<UseIntersectCallback> | UseIntersectCallback = () => {}) {\n  const ref = shallowRef<T>()\n  const intersect = shallowRef(false)\n  let _isIntersected = false\n  let _oldIsIntersected = false\n\n  const loop = useLoop()\n\n  function setup(objOrCientosExposed: ObjOrCientosExposed) {\n    const obj = normalizeCientosInstance(objOrCientosExposed)\n\n    let oldOnRender = obj.onBeforeRender\n\n    const { off: off0 } = loop.onBeforeRender(() => {\n      _isIntersected = false\n\n      // NOTE: If the object is inside the frustum, THREE will call onBeforeRender.\n      oldOnRender = obj.onBeforeRender\n      obj.onBeforeRender = () => (_isIntersected = true)\n    })\n\n    const { off: off1 } = loop.onRender(() => {\n      if (_isIntersected !== _oldIsIntersected) {\n        intersect.value = _isIntersected\n        unref(onChange)?.(_isIntersected)\n        _oldIsIntersected = _isIntersected\n      }\n    })\n\n    return () => {\n      off0()\n      off1()\n      obj.onBeforeRender = oldOnRender\n    }\n  }\n\n  let teardown = () => { }\n\n  watch(ref, () => {\n    teardown()\n    if (ref.value) {\n      teardown = setup(ref.value)\n    }\n  })\n\n  return { ref, intersect, off: () => teardown() }\n}\n"
  },
  {
    "path": "src/core/shapes/Box.vue",
    "content": "<script setup lang=\"ts\">\nimport { type TresColor, useTres } from '@tresjs/core'\nimport { shallowRef, toRefs, watch } from 'vue'\n\nimport type { BoxGeometry } from 'three'\n\nexport interface BoxProps {\n  /**\n   * The width, height and depth of the box.\n   * @default [1, 1, 1]\n   * @type {number[]}\n   * @memberof BoxProps\n   * @see https://threejs.org/docs/#api/en/geometries/BoxGeometry\n   *\n   */\n  args?: ConstructorParameters<typeof BoxGeometry>\n  /**\n   * The color of the box.\n   * @default 0xffffff\n   * @type {TresColor}\n   * @memberof BoxProps\n   * @see https://threejs.org/docs/#api/en/materials/MeshBasicMaterial\n   */\n  color?: TresColor\n}\n\nconst props = withDefaults(defineProps<BoxProps>(), { args: () => [1, 1, 1], color: '#ffffff' })\nconst { invalidate } = useTres()\n\nconst { args, color } = toRefs(props)\nwatch(args, () => {\n  invalidate()\n})\n\nconst boxRef = shallowRef()\n\ndefineExpose({\n  instance: boxRef,\n})\n</script>\n\n<template>\n  <TresMesh\n    ref=\"boxRef\"\n    v-bind=\"$attrs\"\n  >\n    <TresBoxGeometry :args=\"args\" />\n    <slot>\n      <TresMeshBasicMaterial :color=\"color\" />\n    </slot>\n  </TresMesh>\n</template>\n"
  },
  {
    "path": "src/core/shapes/CatmullRomCurve3.vue",
    "content": "<script setup lang=\"ts\">\nimport { CatmullRomCurve3, Vector3 } from 'three'\nimport { computed, shallowRef } from 'vue'\nimport type { TresColor } from '@tresjs/core'\nimport Line2 from './Line2.vue'\n\ntype CurveType = 'centripetal' | 'chordal' | 'catmullrom'\ntype Points = Array<Vector3 | [number, number, number]>\n\ninterface CatmullRomCurve3Props {\n  segments?: number\n  closed?: boolean\n  curveType?: CurveType\n  tension?: number\n\n  // Line2 properties\n  points: Points\n  vertexColors?: TresColor[] | undefined\n  color?: TresColor\n  lineWidth?: number\n  alphaToCoverage?: boolean\n  dashed?: boolean\n  dashSize?: number\n  dashScale?: number\n  dashOffset?: number\n  gapSize?: number\n  worldUnits?: boolean\n}\n\nconst props = withDefaults(defineProps<CatmullRomCurve3Props>(), {\n  segments: 20,\n  closed: false,\n  curveType: 'centripetal',\n  tension: 0.5,\n})\n\nfunction getCatmullRomCurve(points: Points, closed: boolean, curveType: CurveType, tension: number) {\n  const mappedPoints = points.map(pt =>\n    pt instanceof Vector3 ? pt : new Vector3(...(pt as [number, number, number])),\n  )\n\n  return new CatmullRomCurve3(mappedPoints, closed, curveType, tension)\n}\n\nfunction getSegmentedPoints(curve: CatmullRomCurve3, segments: number): Vector3[] {\n  return curve.getPoints(segments)\n}\n\nconst curve = computed(() => getCatmullRomCurve(props.points, props.closed, props.curveType, props.tension))\nconst segmentedPoints = computed(() => getSegmentedPoints(curve.value, props.segments))\n\nconst lineRef = shallowRef()\ndefineExpose({ instance: lineRef })\n</script>\n\n<template>\n  <Line2\n    :ref=\"lineRef\"\n    :points=\"segmentedPoints\"\n    :vertex-colors=\"props.vertexColors\"\n    :color=\"props.color\"\n    :line-width=\"props.lineWidth\"\n    :alpha-to-coverage=\"props.alphaToCoverage\"\n    :dashed=\"props.dashed\"\n    :dash-size=\"props.dashSize\"\n    :dash-scale=\"props.dashScale\"\n    :dash-offset=\"props.dashOffset\"\n    :gap-size=\"props.gapSize\"\n    :world-units=\"props.worldUnits\"\n  />\n</template>\n"
  },
  {
    "path": "src/core/shapes/Circle.vue",
    "content": "<script setup lang=\"ts\">\nimport { type TresColor, useTres } from '@tresjs/core'\nimport { shallowRef, toRefs, watch } from 'vue'\nimport type { CircleGeometry } from 'three'\n\nexport interface CircleProps {\n  /**\n   * The radius, segment, thetaStart, thetaLength of the circle.\n   * @default [1, 32, 0, Math.PI * 2]\n   * @type {any[]}\n   * @memberof CircleProps\n   * @see https://threejs.org/docs/#api/en/geometries/CircleGeometry\n   */\n  args?: ConstructorParameters<typeof CircleGeometry>\n  /**\n   * The color of the circle.\n   * @default 0xffffff\n   * @type {TresColor}\n   * @memberof CircleProps\n   * @see https://threejs.org/docs/#api/en/materials/MeshBasicMaterial\n   */\n  color?: TresColor\n}\n\nconst props = withDefaults(defineProps<CircleProps>(), { args: () => [1, 32, 0, Math.PI * 2], color: '#ffffff' })\nconst { invalidate } = useTres()\n\nconst { args, color } = toRefs(props)\nwatch(args, () => {\n  invalidate()\n})\n\nconst circleRef = shallowRef()\n\ndefineExpose({\n  instance: circleRef,\n})\n</script>\n\n<template>\n  <TresMesh\n    ref=\"circleRef\"\n    v-bind=\"$attrs\"\n  >\n    <TresCircleGeometry :args=\"args\" />\n    <slot>\n      <TresMeshBasicMaterial :color=\"color\" />\n    </slot>\n  </TresMesh>\n</template>\n"
  },
  {
    "path": "src/core/shapes/Cone.vue",
    "content": "<script setup lang=\"ts\">\nimport { type TresColor, useTres } from '@tresjs/core'\nimport { shallowRef, toRefs, watch } from 'vue'\nimport type { ConeGeometry } from 'three'\n\nexport interface ConeProps {\n  /**\n   * The radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength of the cone.\n   * @default [1, 1, 12, 12, false, 0, Math.PI * 2]\n   * @type {any[]}\n   * @memberof ConeProps\n   * @see https://threejs.org/docs/#api/en/geometries/ConeGeometry\n   */\n  args?: ConstructorParameters<typeof ConeGeometry>\n  /**\n   * The color of the cone.\n   * @default 0xffffff\n   * @type {TresColor}\n   * @memberof ConeProps\n   * @see https://threejs.org/docs/#api/en/materials/MeshBasicMaterial\n   */\n  color?: TresColor\n}\n\nconst props = withDefaults(defineProps<ConeProps>(), {\n  args: () => [1, 1, 12, 12, false, 0, Math.PI * 2],\n  color: '#ffffff',\n})\nconst { invalidate } = useTres()\n\nconst { args, color } = toRefs(props)\nwatch(args, () => {\n  invalidate()\n})\n\nconst coneRef = shallowRef()\n\ndefineExpose({\n  instance: coneRef,\n})\n</script>\n\n<template>\n  <TresMesh\n    ref=\"coneRef\"\n    v-bind=\"$attrs\"\n  >\n    <TresConeGeometry :args=\"args\" />\n    <slot>\n      <TresMeshBasicMaterial :color=\"color\" />\n    </slot>\n  </TresMesh>\n</template>\n"
  },
  {
    "path": "src/core/shapes/CubicBezierLine.vue",
    "content": "<script setup lang=\"ts\">\nimport { CubicBezierCurve3, Vector3 } from 'three'\nimport Line2 from './Line2.vue'\nimport { computed, shallowRef } from 'vue'\n\ninterface CubicBezierLineProps {\n  start: Vector3 | [number, number, number]\n  end: Vector3 | [number, number, number]\n  midA: Vector3 | [number, number, number]\n  midB: Vector3 | [number, number, number]\n  segments?: number\n}\n\nconst props = withDefaults(defineProps<CubicBezierLineProps>(), {\n  segments: 20,\n})\n\nconst points = computed(() => {\n  const startV = props.start instanceof Vector3 ? props.start : new Vector3(...props.start)\n  const endV = props.end instanceof Vector3 ? props.end : new Vector3(...props.end)\n  const midAV = props.midA instanceof Vector3 ? props.midA : new Vector3(...props.midA)\n  const midBV = props.midB instanceof Vector3 ? props.midB : new Vector3(...props.midB)\n  return new CubicBezierCurve3(startV, midAV, midBV, endV).getPoints(props.segments)\n})\n\nconst lineRef = shallowRef()\n\ndefineExpose({ instance: lineRef })\n</script>\n\n<template>\n  <Line2 ref=\"lineRef\" :points=\"points\" />\n</template>\n"
  },
  {
    "path": "src/core/shapes/Cylinder.vue",
    "content": "<script setup lang=\"ts\">\nimport { type TresColor, useTres } from '@tresjs/core'\nimport { shallowRef, toRefs, watch } from 'vue'\nimport type { CylinderGeometry } from 'three'\n\nexport interface CylinderProps {\n  /**\n   * The radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength of the cylinder.\n   * @default [1, 1, 1, 32, 1, false, 0, Math.PI * 2]\n   * @type {any[]}\n   * @memberof CylinderProps\n   * @see https://threejs.org/docs/#api/en/geometries/CylinderGeometry\n   */\n  args?: ConstructorParameters<typeof CylinderGeometry>\n  /**\n   * The color of the cylinder.\n   * @default 0xffffff\n   * @type {TresColor}\n   * @memberof CylinderProps\n   * @see https://threejs.org/docs/#api/en/materials/MeshBasicMaterial\n   */\n  color?: TresColor\n}\n\nconst props = withDefaults(defineProps<CylinderProps>(), {\n  args: () => [1, 1, 1, 32, 1, false, 0, Math.PI * 2],\n  color: '#ffffff',\n})\nconst { invalidate } = useTres()\nconst { args, color } = toRefs(props)\nwatch(args, () => {\n  invalidate()\n})\n\nconst cylinderRef = shallowRef()\n\ndefineExpose({\n  instance: cylinderRef,\n})\n</script>\n\n<template>\n  <TresMesh ref=\"cylinderRef\" v-bind=\"$attrs\">\n    <TresCylinderGeometry :args=\"args\" />\n    <slot>\n      <TresMeshBasicMaterial :color=\"color\" />\n    </slot>\n  </TresMesh>\n</template>\n"
  },
  {
    "path": "src/core/shapes/Dodecahedron.vue",
    "content": "<script setup lang=\"ts\">\nimport { type TresColor, useTres } from '@tresjs/core'\nimport { shallowRef, toRefs, watch } from 'vue'\nimport type { DodecahedronGeometry } from 'three'\n\nexport interface DodecahedronProps {\n  /**\n   * The radius and detail of the dodecahedron.\n   * @default [1, 0]\n   * @type {number[]}\n   * @memberof DodecahedronProps\n   * @see https://threejs.org/docs/#api/en/geometries/DodecahedronGeometry\n   */\n  args?: ConstructorParameters<typeof DodecahedronGeometry>\n  /**\n   * The color of the dodecahedron.\n   * @default 0xffffff\n   * @type {TresColor}\n   * @memberof DodecahedronProps\n   * @see https://threejs.org/docs/#api/en/materials/MeshBasicMaterial\n   */\n  color?: TresColor\n}\n\nconst props = withDefaults(defineProps<DodecahedronProps>(), { args: () => [1, 0], color: '#ffffff' })\nconst { invalidate } = useTres()\n\nconst { args, color } = toRefs(props)\nwatch(args, () => {\n  invalidate()\n})\n\nconst dodecahedronRef = shallowRef()\n\ndefineExpose({\n  instance: dodecahedronRef,\n})\n</script>\n\n<template>\n  <TresMesh\n    ref=\"dodecahedronRef\"\n    v-bind=\"$attrs\"\n  >\n    <TresDodecahedronGeometry :args=\"args\" />\n    <slot>\n      <TresMeshBasicMaterial :color=\"color\" />\n    </slot>\n  </TresMesh>\n</template>\n"
  },
  {
    "path": "src/core/shapes/Icosahedron.vue",
    "content": "<script setup lang=\"ts\">\nimport { type TresColor, useTres } from '@tresjs/core'\nimport { shallowRef, toRefs, watch } from 'vue'\nimport type { IcosahedronGeometry } from 'three'\n\nexport interface IcosahedronProps {\n  /**\n   * The radius and detail of the icosahedron.\n   * @default [1, 0]\n   * @type {number[]}\n   * @memberof IcosahedronProps\n   * @see https://threejs.org/docs/#api/en/geometries/IcosahedronGeometry\n   */\n  args?: ConstructorParameters<typeof IcosahedronGeometry>\n  /**\n   * The color of the icosahedron.\n   * @default 0xffffff\n   * @type {TresColor}\n   * @memberof IcosahedronProps\n   * @see https://threejs.org/docs/#api/en/materials/MeshBasicMaterial\n   */\n  color?: TresColor\n}\n\nconst props = withDefaults(defineProps<IcosahedronProps>(), { args: () => [1, 0], color: '#ffffff' })\nconst { invalidate } = useTres()\n\nconst { args, color } = toRefs(props)\nwatch(args, () => {\n  invalidate()\n})\n\nconst icosahedronRef = shallowRef()\n\ndefineExpose({\n  instance: icosahedronRef,\n})\n</script>\n\n<template>\n  <TresMesh\n    ref=\"icosahedronRef\"\n    v-bind=\"$attrs\"\n  >\n    <TresIcosahedronGeometry :args=\"args\" />\n    <slot>\n      <TresMeshBasicMaterial :color=\"color\" />\n    </slot>\n  </TresMesh>\n</template>\n"
  },
  {
    "path": "src/core/shapes/Line2.vue",
    "content": "<script setup lang=\"ts\">\nimport { normalizeColor, useTres } from '@tresjs/core'\nimport { Vector2, Vector3 } from 'three'\nimport { Line2, LineGeometry, LineMaterial } from 'three-stdlib'\nimport { computed, onUnmounted, shallowRef, watch } from 'vue'\nimport type { TresColor } from '@tresjs/core'\nimport type { Color } from 'three'\n\ntype Points = (Vector3 | Vector2 | [number, number, number] | [number, number] | number)[]\ntype VertexColors = Array<TresColor>\nexport interface LineProps {\n  points: Points\n  vertexColors?: VertexColors | null\n  color?: TresColor\n  lineWidth?: number\n  worldUnits?: boolean\n  alphaToCoverage?: boolean\n  dashed?: boolean\n  dashSize?: number\n  gapSize?: number\n  dashScale?: number\n  dashOffset?: number\n}\n\nconst props = withDefaults(defineProps<LineProps>(), {\n  vertexColors: null,\n  color: 'white',\n  lineWidth: 1,\n  worldUnits: false,\n  alphaToCoverage: false,\n  dashed: false,\n  dashSize: 1,\n  gapSize: 1,\n  dashScale: 1,\n  dashOffset: 0,\n})\n\ntype PropsType = typeof props\n\nfunction getInterpolatedVertexColors(vertexColors: VertexColors | null, numPoints: number): Color[] {\n  if (!vertexColors || vertexColors.length === 0) {\n    return Array.from({ length: numPoints }).fill(normalizeColor(props.color)) as Color[]\n  }\n  if (vertexColors.length === 1) {\n    return Array.from({ length: numPoints }).fill(normalizeColor(vertexColors[0])) as Color[]\n  }\n  if (vertexColors.length === numPoints) {\n    return vertexColors.map(normalizeColor)\n  }\n\n  const numSegments = numPoints - 1\n  const mappedColors = vertexColors.map(normalizeColor)\n  if (closed) { mappedColors.push(mappedColors[0].clone()) }\n\n  const iColors: Color[] = [mappedColors[0]]\n  const divisions = numSegments / (mappedColors.length - 1)\n  for (let i = 1; i < numSegments; i++) {\n    const alpha = (i % divisions) / divisions\n    const colorIndex = Math.floor(i / divisions)\n    iColors.push(mappedColors[colorIndex].clone().lerp(mappedColors[colorIndex + 1], alpha))\n  }\n  iColors.push(mappedColors[mappedColors.length - 1])\n\n  return iColors\n}\n\nconst lineMaterial = new LineMaterial()\nconst lineGeometry = new LineGeometry()\nconst line = new Line2(lineGeometry, lineMaterial)\nconst { sizes, invalidate } = useTres()\nconst hasVertexColors = computed(() => Array.isArray(props.vertexColors))\n\nfunction updateLineMaterial(material: LineMaterial, props: PropsType) {\n  material.color = normalizeColor(props.color)\n  material.linewidth = props.lineWidth\n  material.alphaToCoverage = props.alphaToCoverage\n  material.worldUnits = props.worldUnits\n  material.vertexColors = Array.isArray(props.vertexColors)\n  material.dashed = props.dashed\n  material.dashScale = props.dashScale\n  material.dashSize = props.dashSize\n  material.dashOffset = props.dashOffset\n  material.gapSize = props.gapSize\n  material.needsUpdate = true\n}\n\nfunction updateLineGeometry(geometry: LineGeometry, points: Points, vertexColors: VertexColors | null) {\n  const pValues = points.map((p) => {\n    if (p instanceof Vector3) {\n      return [p.x, p.y, p.z]\n    }\n    else if (p instanceof Vector2) {\n      return [p.x, p.y, 0]\n    }\n    else if (Array.isArray(p) && p.length === 2) {\n      return [p[0], p[1], 0]\n    }\n    else {\n      return p\n    }\n  }).flat()\n  geometry.setPositions(pValues.flat())\n\n  const colors = getInterpolatedVertexColors(vertexColors, points.length).map(c => c.toArray()).flat()\n  geometry.setColors(colors)\n\n  line.computeLineDistances()\n}\n\nupdateLineMaterial(lineMaterial, props)\nupdateLineGeometry(lineGeometry, props.points, props.vertexColors)\nline.computeLineDistances()\n\nwatch(() => [\n  props.color,\n  props.lineWidth,\n  props.alphaToCoverage,\n  props.worldUnits,\n  hasVertexColors,\n  props.dashed,\n  props.dashScale,\n  props.dashSize,\n  props.dashOffset,\n], () => {\n  updateLineMaterial(lineMaterial, props)\n  invalidate()\n})\nwatch(() => [props.points, props.vertexColors], () => {\n  updateLineGeometry(lineGeometry, props.points, props.vertexColors)\n  invalidate()\n})\nwatch(() => [sizes.height, sizes.width], () => {\n  lineMaterial.resolution = new Vector2(sizes.width.value, sizes.height.value)\n  invalidate()\n})\n\nonUnmounted(() => {\n  lineGeometry.dispose()\n  lineMaterial.dispose()\n})\n\nconst lineRef = shallowRef()\ndefineExpose({ instance: lineRef })\n</script>\n\n<template>\n  <primitive\n    :ref=\"lineRef\"\n    :object=\"line\"\n  />\n</template>\n"
  },
  {
    "path": "src/core/shapes/Octahedron.vue",
    "content": "<script setup lang=\"ts\">\nimport { type TresColor, useTres } from '@tresjs/core'\nimport { shallowRef, toRefs, watch } from 'vue'\nimport type { OctahedronGeometry } from 'three'\n\nexport interface OctahedronProps {\n  /**\n   * The radius and detail of the octahedron.\n   * @default [1, 0]\n   * @type {number[]}\n   * @memberof OctahedronProps\n   * @see https://threejs.org/docs/#api/en/geometries/OctahedronGeometry\n   */\n  args?: ConstructorParameters<typeof OctahedronGeometry>\n  /**\n   * The color of the octahedron.\n   * @default 0xffffff\n   * @type {TresColor}\n   * @memberof OctahedronProps\n   * @see https://threejs.org/docs/#api/en/materials/MeshBasicMaterial\n   */\n  color?: TresColor\n}\n\nconst props = withDefaults(defineProps<OctahedronProps>(), { args: () => [1, 0], color: '#ffffff' })\nconst { invalidate } = useTres()\n\nconst { args, color } = toRefs(props)\nwatch(args, () => {\n  invalidate()\n})\n\nconst octahedronRef = shallowRef()\n\ndefineExpose({\n  instance: octahedronRef,\n})\n</script>\n\n<template>\n  <TresMesh\n    ref=\"octahedronRef\"\n    v-bind=\"$attrs\"\n  >\n    <TresOctahedronGeometry :args=\"args\" />\n    <slot>\n      <TresMeshBasicMaterial :color=\"color\" />\n    </slot>\n  </TresMesh>\n</template>\n"
  },
  {
    "path": "src/core/shapes/Plane.vue",
    "content": "<script setup lang=\"ts\">\nimport { type TresColor, useTres } from '@tresjs/core'\nimport { shallowRef, toRefs, watch } from 'vue'\nimport type { PlaneGeometry } from 'three'\n\nexport interface PlaneProps {\n  /**\n   * The width, height, widthSegments and heightSegments of the plane.\n   * @default [1, 1, 1, 1]\n   * @type {number[]}\n   * @memberof PlaneProps\n   * @see https://threejs.org/docs/#api/en/geometries/PlaneGeometry\n   */\n  args?: ConstructorParameters<typeof PlaneGeometry>\n  /**\n   * The color of the plane.\n   * @default 0xffffff\n   * @type {TresColor}\n   * @memberof PlaneProps\n   * @see https://threejs.org/docs/#api/en/materials/MeshBasicMaterial\n   */\n  color?: TresColor\n}\n\nconst props = withDefaults(defineProps<PlaneProps>(), { args: () => [1, 1], color: '#ffffff' })\nconst { invalidate } = useTres()\n\nconst { args, color } = toRefs(props)\nwatch(args, () => {\n  invalidate()\n})\n\nconst planeRef = shallowRef()\n\ndefineExpose({\n  instance: planeRef,\n})\n</script>\n\n<template>\n  <TresMesh\n    ref=\"planeRef\"\n    :rotation=\"[-Math.PI / 2, 0, 0]\"\n    v-bind=\"$attrs\"\n  >\n    <TresPlaneGeometry :args=\"args\" />\n    <slot>\n      <TresMeshBasicMaterial :color=\"color\" />\n    </slot>\n  </TresMesh>\n</template>\n"
  },
  {
    "path": "src/core/shapes/QuadraticBezierLine.vue",
    "content": "<script setup lang=\"ts\">\nimport { QuadraticBezierCurve3, Vector3 } from 'three'\nimport Line2 from './Line2.vue'\nimport { computed, shallowRef } from 'vue'\n\ninterface QuadraticBezierLineProps {\n  start: Vector3 | [number, number, number]\n  end: Vector3 | [number, number, number]\n  mid?: Vector3 | [number, number, number]\n  segments?: number\n}\n\nconst props = withDefaults(defineProps<QuadraticBezierLineProps>(), {\n  segments: 20,\n})\n\nconst points = computed(() => {\n  const startV = props.start instanceof Vector3 ? props.start : new Vector3(...props.start)\n  const endV = props.end instanceof Vector3 ? props.end : new Vector3(...props.end)\n  const mid = props.mid instanceof Vector3 ? props.mid : (Array.isArray(props.mid) ? new Vector3(...props.mid) : new Vector3(endV.x, startV.y, endV.z))\n  return new QuadraticBezierCurve3(startV, mid, endV).getPoints(props.segments)\n})\n\nconst lineRef = shallowRef()\n\ndefineExpose({ instance: lineRef })\n</script>\n\n<template>\n  <Line2 ref=\"lineRef\" :points=\"points\" />\n</template>\n"
  },
  {
    "path": "src/core/shapes/Ring.vue",
    "content": "<script setup lang=\"ts\">\nimport { type TresColor, useTres } from '@tresjs/core'\nimport { shallowRef, toRefs, watch } from 'vue'\nimport type { RingGeometry } from 'three'\n\nexport interface RingProps {\n  /**\n   * The innerRadius, outerRadius, thetaSegments, phiSegments, tethaStart, thetaLength of the ring.\n   * @default [0.5, 1, 32, 1, 0, Math.PI * 2]\n   * @type {number[]}\n   * @memberof RingProps\n   * @see https://threejs.org/docs/#api/en/geometries/RingGeometry\n   */\n  args?: ConstructorParameters<typeof RingGeometry>\n  /**\n   * The color of the ring.\n   * @default 0xffffff\n   * @type {TresColor}\n   * @memberof RingProps\n   * @see https://threejs.org/docs/#api/en/materials/MeshBasicMaterial\n   */\n  color?: TresColor\n}\n\nconst props = withDefaults(defineProps<RingProps>(), { args: () => [0.5, 1, 32], color: '#ffffff' })\n\nconst { args, color } = toRefs(props)\n\nconst { invalidate } = useTres()\n\nwatch(args, () => {\n  invalidate()\n})\n\nconst ringRef = shallowRef()\n\ndefineExpose({\n  instance: ringRef,\n})\n</script>\n\n<template>\n  <TresMesh\n    ref=\"ringRef\"\n    v-bind=\"$attrs\"\n  >\n    <TresRingGeometry :args=\"args\" />\n    <slot>\n      <TresMeshBasicMaterial :color=\"color\" />\n    </slot>\n  </TresMesh>\n</template>\n"
  },
  {
    "path": "src/core/shapes/RoundedBox.vue",
    "content": "<script setup lang=\"ts\">\nimport { useTres } from '@tresjs/core'\nimport { RoundedBoxGeometry } from 'three-stdlib'\nimport { shallowRef, toRefs, watch } from 'vue'\nimport type { TresColor } from '@tresjs/core'\n\nimport type { BoxGeometry } from 'three'\n\nexport interface BoxProps {\n  /**\n   * The width, height, depth, segments and radius.\n   * @default [1, 1, 1, 2, 0.1]\n   * @type {number[]}\n   * @memberof BoxProps\n   * @see https://github.com/mrdoob/three.js/blob/master/examples/jsm/geometries/RoundedBoxGeometry.js\n   *\n   */\n  args?: ConstructorParameters<typeof BoxGeometry>\n  /**\n   * The color of the box.\n   * @default 0xffffff\n   * @type {TresColor}\n   * @memberof BoxProps\n   * @see https://threejs.org/docs/#api/en/materials/MeshBasicMaterial\n   */\n  color?: TresColor\n}\n\nconst props = withDefaults(defineProps<BoxProps>(), { args: () => [1, 1, 1, 2, 0.1], color: '#ffffff' })\n\nconst { args, color } = toRefs(props)\nconst { invalidate, extend } = useTres()\n\nextend({ RoundedBoxGeometry })\nwatch(args, () => {\n  invalidate()\n})\nconst roundedBoxRef = shallowRef()\n\ndefineExpose({ instance: roundedBoxRef })\n</script>\n\n<template>\n  <TresMesh ref=\"roundedBoxRef\">\n    <TresRoundedBoxGeometry :args=\"args\" />\n    <slot>\n      <TresMeshBasicMaterial :color=\"color\" />\n    </slot>\n  </TresMesh>\n</template>\n"
  },
  {
    "path": "src/core/shapes/ScreenQuad.vue",
    "content": "<script setup lang=\"ts\">\n// NOTE:\n// Based on https://github.com/pmndrs/drei/blob/master/src/core/ScreenQuad.tsx\n// reference https://medium.com/@luruke/simple-postprocessing-in-three-js-91936ecadfb7\n// and @gsimone ;)\nimport * as THREE from 'three'\nimport { shallowRef } from 'vue'\n\nconst geometry = new THREE.BufferGeometry()\nconst vertices = new Float32Array([-1, -1, 3, -1, -1, 3])\ngeometry.boundingSphere = new THREE.Sphere()\ngeometry.boundingSphere.set(new THREE.Vector3(), Infinity)\ngeometry.setAttribute('position', new THREE.BufferAttribute(vertices, 2))\n\nconst meshRef = shallowRef()\ndefineExpose({ instance: meshRef })\n</script>\n\n<template>\n  <TresMesh ref=\"meshRef\" :geometry=\"geometry\" :frustum-culled=\"false\">\n    <slot></slot>\n  </TresMesh>\n</template>\n"
  },
  {
    "path": "src/core/shapes/Sphere.vue",
    "content": "<script setup lang=\"ts\">\nimport { type TresColor, useTres } from '@tresjs/core'\nimport { shallowRef, toRefs, watch } from 'vue'\nimport type { SphereGeometry } from 'three'\n\nexport interface SphereProps {\n  /**\n   * The radius, widthSegments, heightSegments, phiStart phiLength,\n   * thetaStart and thetaLength of the sphere.\n   * @default [2, 32, 16, 0, Math.PI * 2, 0, Math.PI]\n   * @type {number[]}\n   * @memberof SphereProps\n   * @see https://threejs.org/docs/#api/en/geometries/SphereGeometry\n   */\n  args?: ConstructorParameters<typeof SphereGeometry>\n  /**\n   * The color of the sphere.\n   * @default 0xffffff\n   * @type {TresColor}\n   * @memberof SphereProps\n   * @see https://threejs.org/docs/#api/en/materials/MeshBasicMaterial\n   */\n  color?: TresColor\n}\n\nconst props = withDefaults(defineProps<SphereProps>(), { args: () => [2, 32, 16], color: '#ffffff' })\nconst { invalidate } = useTres()\n\nconst { args, color } = toRefs(props)\nwatch(args, () => {\n  invalidate()\n})\n\nconst sphereRef = shallowRef()\n\ndefineExpose({\n  instance: sphereRef,\n})\n</script>\n\n<template>\n  <TresMesh\n    ref=\"sphereRef\"\n    v-bind=\"$attrs\"\n  >\n    <TresSphereGeometry :args=\"args\" />\n    <slot>\n      <TresMeshBasicMaterial :color=\"color\" />\n    </slot>\n  </TresMesh>\n</template>\n"
  },
  {
    "path": "src/core/shapes/Superformula.vue",
    "content": "<script setup lang=\"ts\">\nimport { type TresColor, useTres } from '@tresjs/core'\nimport { BufferAttribute, BufferGeometry } from 'three'\nimport { onUnmounted, shallowRef, watch } from 'vue'\n\nexport type Float3 = [number, number, number]\n\nexport interface SuperFormulaProps {\n  /**\n   * Number of horizontal mesh segments\n   */\n  widthSegments?: number\n  /**\n   * Number of vertical mesh segments\n   */\n  heightSegments?: number\n  /**\n   * The 3D Superformula is the spherical product of 2 2D superformula curves: here called curves \"A\" and \"B\".\n   * Number of radial arms/ripples of A, corresponding to \"m\" [in this article.](https://en.wikipedia.org/wiki/Superformula)\n   */\n  numArmsA?: number\n  /**\n   * A's 3 exponents\n   */\n  expA?: Float3\n  /**\n   * For B, number of radial arms/ripples\n   */\n  numArmsB?: number\n  /**\n   * B's 3 exponents\n   */\n  expB?: Float3\n  /**\n   * If no material is provided, a color for the default material\n   */\n  color?: TresColor\n}\n\nconst props = withDefaults(defineProps<SuperFormulaProps>(), {\n  widthSegments: 32,\n  heightSegments: 32,\n  numArmsA: 4,\n  expA: () => [40, 1.3, 0.9],\n  numArmsB: 4,\n  expB: () => [40, 1.3, 0.9],\n  color: 'white',\n})\n\nconst { invalidate } = useTres()\n\nconst { cos, sin, abs } = Math\n\nconst geometry = shallowRef()\nconst color = shallowRef(props.color)\n\nfunction makeGeometry(widthSegments: number, heightSegments: number) {\n  const geometry = new BufferGeometry()\n  const numPoints = widthSegments * heightSegments\n  const vertices = new Float32Array(Array.from({ length: 3 * numPoints }).fill(0) as number[])\n  const normals = new Float32Array(Array.from({ length: 3 * numPoints }).fill(0) as number[])\n  const indices: number[] = []\n  for (let h = 0; h < heightSegments - 1; h++) {\n    for (let w = 0; w < widthSegments - 1; w++) {\n      const tl = h * widthSegments + w\n      const tr = tl + 1\n      const bl = tl + widthSegments\n      const br = tr + widthSegments\n      indices.push(tl, bl, tr)\n      indices.push(bl, br, tr)\n    }\n    const tl = h * widthSegments + widthSegments - 1\n    const tr = h * widthSegments\n    const bl = tl + widthSegments\n    const br = tr + widthSegments\n    indices.push(tl, bl, tr)\n    indices.push(bl, br, tr)\n  }\n  geometry.setIndex(indices)\n  geometry.setAttribute('position', new BufferAttribute(vertices, 3))\n  geometry.setAttribute('normal', new BufferAttribute(normals, 3))\n  return geometry\n}\n\n// Source:\n// https://en.wikipedia.org/wiki/Superformula\n// NOTE: Superformula 2D\nfunction r(theta: number, numArms: number, exp1: number, exp2: number, exp3: number): number {\n  return (abs(cos(numArms * theta * 0.25)) ** exp2 + abs(sin(numArms * theta * 0.25)) ** exp3) ** (-1 / exp1)\n}\n\n// NOTE: Superformula 3D\nfunction updateGeometry(geometry: BufferGeometry, numArmsA: number, expA1: number, expA2: number, expA3: number, numArmsB: number, expB1: number, expB2: number, expB3: number, widthSegments: number, heightSegments: number) {\n  const thetaStep = 2 * Math.PI / widthSegments\n  const thetaStart = -Math.PI\n  const phiStep = Math.PI / (heightSegments - 1)\n  const phiStart = -0.5 * Math.PI\n  const positionAttribute = geometry.getAttribute('position')\n\n  let i = 0\n  let theta = 0\n  let phi = phiStart\n  for (let pi = 0; pi < heightSegments; pi++) {\n    theta = thetaStart\n    for (let ti = 0; ti < widthSegments; ti++) {\n      const rA = r(theta, numArmsA, expA1, expA2, expA3)\n      const rB = r(phi, numArmsB, expB1, expB2, expB3)\n      positionAttribute.setXYZ(\n        i,\n        rA * cos(theta) * rB * cos(phi),\n        rB * sin(phi),\n        rA * sin(theta) * rB * cos(phi),\n      )\n      i++\n      theta += thetaStep\n    }\n    phi += phiStep\n  }\n  positionAttribute.needsUpdate = true\n  geometry.computeVertexNormals()\n}\n\nwatch(() => props.color, () => color.value = props.color)\n\nwatch(() => [props.widthSegments, props.heightSegments], () => {\n  if (geometry.value) {\n    geometry.value.dispose()\n  }\n  geometry.value = makeGeometry(props.widthSegments, props.heightSegments)\n  invalidate()\n}, { immediate: true })\n\nwatch(() => [\n  props.numArmsA,\n  props.expA[0],\n  props.expA[1],\n  props.expA[2],\n  props.numArmsB,\n  props.expB[0],\n  props.expB[1],\n  props.expB[2],\n], () => {\n  updateGeometry(geometry.value, props.numArmsA, props.expA[0], props.expA[1], props.expA[2], props.numArmsB, props.expB[0], props.expB[1], props.expB[2], props.widthSegments, props.heightSegments)\n  invalidate()\n}, { immediate: true })\n\nonUnmounted(() => {\n  if (geometry.value) {\n    geometry.value.dispose()\n  }\n})\n\nconst superformulaRef = shallowRef()\n\ndefineExpose({\n  instance: superformulaRef,\n})\n</script>\n\n<template>\n  <TresMesh\n    ref=\"superformulaRef\"\n    v-bind=\"$attrs\"\n    :geometry=\"geometry\"\n  >\n    <slot>\n      <TresMeshBasicMaterial :color=\"color\" />\n    </slot>\n  </TresMesh>\n</template>\n"
  },
  {
    "path": "src/core/shapes/Tetrahedron.vue",
    "content": "<script setup lang=\"ts\">\nimport { type TresColor, useTres } from '@tresjs/core'\nimport { shallowRef, toRefs, watch } from 'vue'\nimport type { TetrahedronGeometry } from 'three'\n\nexport interface TetrahedronProps {\n  /**\n   * The radius and detail of the tetrahedron.\n   * @default [1, 0]\n   * @type {number[]}\n   * @memberof TetrahedronProps\n   * @see https://threejs.org/docs/#api/en/geometries/TetrahedronGeometry\n   */\n  args?: ConstructorParameters<typeof TetrahedronGeometry>\n  /**\n   * The color of the tetrahedron.\n   * @default 0xffffff\n   * @type {TresColor}\n   * @memberof TetrahedronProps\n   * @see https://threejs.org/docs/#api/en/materials/MeshBasicMaterial\n   */\n  color?: TresColor\n}\n\nconst props = withDefaults(defineProps<TetrahedronProps>(), { args: () => [1, 0], color: '#ffffff' })\nconst { invalidate } = useTres()\n\nconst { args, color } = toRefs(props)\nwatch(args, () => {\n  invalidate()\n})\n\nconst tetrahedronRef = shallowRef()\n\ndefineExpose({\n  instance: tetrahedronRef,\n})\n</script>\n\n<template>\n  <TresMesh\n    ref=\"tetrahedronRef\"\n    :rotation=\"[-Math.PI / 2, 0, 0]\"\n    v-bind=\"$attrs\"\n  >\n    <TresTetrahedronGeometry :args=\"args\" />\n    <slot>\n      <TresMeshBasicMaterial :color=\"color\" />\n    </slot>\n  </TresMesh>\n</template>\n"
  },
  {
    "path": "src/core/shapes/Torus.vue",
    "content": "<script setup lang=\"ts\">\nimport { type TresColor, useTres } from '@tresjs/core'\nimport { shallowRef, toRefs, watch } from 'vue'\nimport type { TorusGeometry } from 'three'\n\nexport interface TorusProps {\n  /**\n   * The radius, tube, radialSegments, tubularSegments, arc of the torus.\n   * @default [1, 1, 16, 80, Math.PI * 2]\n   * @type {number[]}\n   * @memberof TorusProps\n   * @see https://threejs.org/docs/#api/en/geometries/TorusGeometry\n   */\n  args?: ConstructorParameters<typeof TorusGeometry>\n  /**\n   * The color of the torus.\n   * @default 0xffffff\n   * @type {TresColor}\n   * @memberof TorusProps\n   * @see https://threejs.org/docs/#api/en/materials/MeshBasicMaterial\n   */\n  color?: TresColor\n}\n\nconst props = withDefaults(defineProps<TorusProps>(), { args: () => [1, 1, 16, 80], color: '#ffffff' })\nconst { args, color } = toRefs(props)\nconst { invalidate } = useTres()\nwatch(args, () => {\n  invalidate()\n})\n\nconst torusRef = shallowRef()\n\ndefineExpose({\n  instance: torusRef,\n})\n</script>\n\n<template>\n  <TresMesh\n    ref=\"torusRef\"\n    v-bind=\"$attrs\"\n  >\n    <TresTorusGeometry :args=\"args\" />\n    <slot>\n      <TresMeshBasicMaterial :color=\"color\" />\n    </slot>\n  </TresMesh>\n</template>\n"
  },
  {
    "path": "src/core/shapes/TorusKnot.vue",
    "content": "<script setup lang=\"ts\">\nimport { type TresColor, useTres } from '@tresjs/core'\nimport { shallowRef, toRefs, watch } from 'vue'\nimport type { TorusKnotGeometry } from 'three'\n\nexport interface TorusKnotProps {\n  /**\n   * The radius, tube, radialSegments, tubularSegments and p, q of the torus knot.\n   * @default [1, 0.4, 64, 8, 2, 3]\n   * @type {number[]}\n   * @memberof TorusKnotProps\n   * @see https://threejs.org/docs/#api/en/geometries/TorusKnotGeometry\n   */\n  args?: ConstructorParameters<typeof TorusKnotGeometry>\n  /**\n   * The color of the torus knot.\n   * @default 0xffffff\n   * @type {TresColor}\n   * @memberof TorusKnotProps\n   * @see https://threejs.org/docs/#api/en/materials/MeshBasicMaterial\n   */\n  color?: TresColor\n}\n\nconst props = withDefaults(defineProps<TorusKnotProps>(), { args: () => [1, 0.4, 64, 8], color: '#ffffff' })\nconst { args, color } = toRefs(props)\nconst { invalidate } = useTres()\n\nwatch(args, () => {\n  invalidate()\n})\n\nconst torusKnotRef = shallowRef()\n\ndefineExpose({\n  instance: torusKnotRef,\n})\n</script>\n\n<template>\n  <TresMesh\n    ref=\"torusKnotRef\"\n    v-bind=\"$attrs\"\n  >\n    <TresTorusKnotGeometry :args=\"args\" />\n    <slot>\n      <TresMeshBasicMaterial :color=\"color\" />\n    </slot>\n  </TresMesh>\n</template>\n"
  },
  {
    "path": "src/core/shapes/Tube.vue",
    "content": "<!-- eslint-disable max-len -->\n<script setup lang=\"ts\">\nimport { type TresColor, useTres } from '@tresjs/core'\nimport { QuadraticBezierCurve3, Vector3 } from 'three'\nimport { shallowRef, toRefs, watch } from 'vue'\nimport type { TubeGeometry } from 'three'\n\nexport interface TubeProps {\n  /**\n   * The curve, segments, radius, radialSegments, closed.\n   * @default [new QuadraticBezierCurve3(new Vector3(-1, 0, 0), new Vector3(0, 1, 0), new Vector3(1, 0, 0)), 20, 0.2, 8, false]\n   * @type {TubeGeometryParams}\n   * @memberof TubeProps\n   * @see https://threejs.org/docs/#api/en/geometries/TubeGeometry\n   */\n  args?: ConstructorParameters<typeof TubeGeometry>\n  /**\n   * The color of the tube.\n   * @default 0xffffff\n   * @type {TresColor}\n   * @memberof TubeProps\n   * @see https://threejs.org/docs/#api/en/materials/MeshBasicMaterial\n   */\n  color?: TresColor\n}\n\nconst props = withDefaults(defineProps<TubeProps>(), {\n  args: () => [\n    new QuadraticBezierCurve3(new Vector3(-1, 0, 0), new Vector3(0, 1, 0), new Vector3(1, 0, 0)),\n    20,\n    0.2,\n    8,\n    false,\n  ],\n  color: '#ffffff',\n})\nconst { invalidate } = useTres()\n\nconst { args, color } = toRefs(props)\nwatch(args, () => {\n  invalidate()\n})\n\nconst tubeRef = shallowRef()\n\ndefineExpose({\n  instance: tubeRef,\n})\n</script>\n\n<template>\n  <TresMesh\n    ref=\"tubeRef\"\n    v-bind=\"$attrs\"\n  >\n    <TresTubeGeometry :args=\"args\" />\n    <slot>\n      <TresMeshBasicMaterial :color=\"color\" />\n    </slot>\n  </TresMesh>\n</template>\n"
  },
  {
    "path": "src/core/shapes/index.ts",
    "content": "import Box from './Box.vue'\nimport CatmullRomCurve3 from './CatmullRomCurve3.vue'\nimport Circle from './Circle.vue'\nimport Cone from './Cone.vue'\nimport QuadraticBezierLine from './QuadraticBezierLine.vue'\nimport CubicBezierLine from './CubicBezierLine.vue'\nimport Cylinder from './Cylinder.vue'\nimport Dodecahedron from './Dodecahedron.vue'\nimport Icosahedron from './Icosahedron.vue'\nimport Line2 from './Line2.vue'\nimport Octahedron from './Octahedron.vue'\nimport Plane from './Plane.vue'\nimport Ring from './Ring.vue'\nimport RoundedBox from './RoundedBox.vue'\nimport ScreenQuad from './ScreenQuad.vue'\nimport Sphere from './Sphere.vue'\nimport Superformula from './Superformula.vue'\nimport Tetrahedron from './Tetrahedron.vue'\nimport Torus from './Torus.vue'\nimport TorusKnot from './TorusKnot.vue'\nimport Tube from './Tube.vue'\n\nexport {\n  Box,\n  CatmullRomCurve3,\n  Circle,\n  Cone,\n  CubicBezierLine,\n  Cylinder,\n  Dodecahedron,\n  Icosahedron,\n  Line2,\n  Octahedron,\n  Plane,\n  QuadraticBezierLine,\n  Ring,\n  RoundedBox,\n  ScreenQuad,\n  Sphere,\n  Superformula,\n  Tetrahedron,\n  Torus,\n  TorusKnot,\n  Tube,\n}\n"
  },
  {
    "path": "src/core/staging/AccumulativeShadows/ProgressiveLightMap.ts",
    "content": "import type { Camera, Group, Light, Material, Mesh, Scene, ShaderMaterial, Texture, WebGLRenderer } from 'three'\nimport { Color, HalfFloatType, MeshLambertMaterial, NearestFilter, WebGLRenderTarget } from 'three'\nimport { MeshDiscardMaterial as DiscardMaterial } from '../../materials/meshDiscardMaterial/material'\n\nfunction isLight(object: any): object is Light {\n  return object.isLight\n}\n\nfunction isGeometry(object: any): object is Mesh {\n  return !!object.geometry\n}\n\n// NOTE: Based on \"Progressive Light Map Accumulator\", by [zalo](https://github.com/zalo/)\nexport class ProgressiveLightMap {\n  renderer: WebGLRenderer\n  res: number\n  scene: Scene\n  object: Mesh | null\n  lightsGroup: Group | null = null\n  buffer1Active: boolean\n  progressiveLightMap1: WebGLRenderTarget\n  progressiveLightMap2: WebGLRenderTarget\n  discardMat: ShaderMaterial\n  targetMat: MeshLambertMaterial\n  previousShadowMap: { value: Texture }\n  averagingWindow: { value: number }\n  clearColor: Color\n  clearAlpha: number\n  lights: { object: Light, intensity: number }[]\n  meshes: { object: Mesh, material: Material | Material[] }[]\n\n  constructor(renderer: WebGLRenderer, scene: Scene, res = 1024) {\n    this.renderer = renderer\n    this.res = res\n    this.scene = scene\n    this.buffer1Active = false\n    this.lights = []\n    this.meshes = []\n    this.object = null\n    this.clearColor = new Color()\n    this.clearAlpha = 0\n\n    // NOTE: Create the Progressive LightMap Texture\n    const textureParams = {\n      type: HalfFloatType,\n      magFilter: NearestFilter,\n      minFilter: NearestFilter,\n    }\n    this.progressiveLightMap1 = new WebGLRenderTarget(this.res, this.res, textureParams)\n    this.progressiveLightMap2 = new WebGLRenderTarget(this.res, this.res, textureParams)\n\n    // NOTE: Inject some spicy new logic into a standard phong material\n    this.discardMat = new DiscardMaterial()\n    this.targetMat = new MeshLambertMaterial({ fog: false })\n    this.previousShadowMap = { value: this.progressiveLightMap1.texture }\n    this.averagingWindow = { value: 100 }\n    this.targetMat.onBeforeCompile = (shader) => {\n      // NOTE: Vertex Shader: Set Vertex Positions to the Unwrapped UV Positions\n      shader.vertexShader\n        = `varying vec2 vUv;\n        ${shader.vertexShader.slice(0, -1)}\n        vUv = uv; \n        gl_Position = vec4((uv - 0.5) * 2.0, 1.0, 1.0); }`\n\n      // NOTE: Fragment Shader: Set Pixels to average in the Previous frame's Shadows\n      const bodyStart = shader.fragmentShader.indexOf('void main() {')\n      shader.fragmentShader\n        = `\n        varying vec2 vUv;\n        ${shader.fragmentShader.slice(0, bodyStart)}\n        uniform sampler2D previousShadowMap;\n        uniform float averagingWindow;\n        ${shader.fragmentShader.slice(bodyStart - 1, -1)}\n        vec3 texelOld = texture2D(previousShadowMap, vUv).rgb;\n        gl_FragColor.rgb = mix(texelOld, gl_FragColor.rgb, 1.0 / averagingWindow);\n      }`\n\n      // NOTE: Set the Previous Frame's Texture Buffer and Averaging Window\n      shader.uniforms.previousShadowMap = this.previousShadowMap\n      shader.uniforms.averagingWindow = this.averagingWindow\n    }\n  }\n\n  clear() {\n    this.renderer.getClearColor(this.clearColor)\n    this.clearAlpha = this.renderer.getClearAlpha()\n    this.renderer.setClearColor('black', 1)\n    this.renderer.setRenderTarget(this.progressiveLightMap1)\n    this.renderer.clear()\n    this.renderer.setRenderTarget(this.progressiveLightMap2)\n    this.renderer.clear()\n    this.renderer.setRenderTarget(null)\n    this.renderer.setClearColor(this.clearColor, this.clearAlpha)\n\n    this.lights = []\n    this.meshes = []\n    this.scene.traverse((object) => {\n      if (object === this.lightsGroup) { return false }\n      if (isGeometry(object)) {\n        this.meshes.push({ object, material: object.material })\n      }\n      else if (isLight(object)) {\n        this.lights.push({ object, intensity: object.intensity })\n      }\n    })\n  }\n\n  prepare() {\n    this.lights.forEach(light => (light.object.intensity = 0))\n    this.meshes.forEach(mesh => (mesh.object.material = this.discardMat))\n  }\n\n  finish() {\n    this.lights.forEach(light => (light.object.intensity = light.intensity))\n    this.meshes.forEach(mesh => (mesh.object.material = mesh.material))\n  }\n\n  configure(object: Mesh, lightsGroup: Group) {\n    this.object = object\n    this.lightsGroup = lightsGroup\n  }\n\n  update(camera: Camera, blendWindow = 100) {\n    if (!this.object) { return }\n    // NOTE: Set each object's material to the UV Unwrapped Surface Mapping Version\n    this.averagingWindow.value = blendWindow\n    this.object.material = this.targetMat\n    // NOTE: Ping-pong two surface buffers for reading/writing\n    const activeMap = this.buffer1Active ? this.progressiveLightMap1 : this.progressiveLightMap2\n    const inactiveMap = this.buffer1Active ? this.progressiveLightMap2 : this.progressiveLightMap1\n    // NOTE: Render the object's surface maps\n    const oldBg = this.scene.background\n    this.scene.background = null\n    this.renderer.setRenderTarget(activeMap)\n    this.previousShadowMap.value = inactiveMap.texture\n    this.buffer1Active = !this.buffer1Active\n    this.renderer.render(this.scene, camera)\n    this.renderer.setRenderTarget(null)\n    this.scene.background = oldBg\n  }\n}\n"
  },
  {
    "path": "src/core/staging/AccumulativeShadows/SoftShadowMaterial.ts",
    "content": "import { shaderMaterial } from '../../../utils/shaderMaterial'\nimport type { ColorRepresentation, Texture } from 'three'\nimport { Color } from 'three'\n\nexport interface SoftShadowMaterialProps {\n  map: Texture\n  color?: ColorRepresentation\n  alphaTest?: number\n  blend?: number\n}\n\nexport const SoftShadowMaterial = /* @__PURE__ */ shaderMaterial(\n  {\n    color: new Color(),\n    blend: 2.0,\n    alphaTest: 0.75,\n    opacity: 0,\n    map: null,\n  },\n  `varying vec2 vUv;\n   void main() {\n     gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(position, 1.);\n     vUv = uv;\n   }`,\n  `varying vec2 vUv;\n   uniform sampler2D map;\n   uniform vec3 color;\n   uniform float opacity;\n   uniform float alphaTest;\n   uniform float blend;\n   void main() {\n     vec4 sampledDiffuseColor = texture2D(map, vUv);\n     gl_FragColor = vec4(color * sampledDiffuseColor.r * blend, max(0.0, (1.0 - (sampledDiffuseColor.r + sampledDiffuseColor.g + sampledDiffuseColor.b) / alphaTest)) * opacity);\n     #include <tonemapping_fragment>\n     #include <colorspace_fragment>\n   }`,\n)\n"
  },
  {
    "path": "src/core/staging/AccumulativeShadows/component.vue",
    "content": "<script setup lang=\"ts\">\nimport { computed, shallowRef, watch, watchEffect } from 'vue'\nimport type { ColorRepresentation, Mesh, PlaneGeometry, ShaderMaterial, Texture, WebGLRenderer } from 'three'\nimport { Group } from 'three'\nimport { extend, useLoop, useTres } from '@tresjs/core'\nimport RandomizedLights from '../RandomizedLights/component.vue'\nimport { ProgressiveLightMap } from './ProgressiveLightMap'\nimport { SoftShadowMaterial } from './SoftShadowMaterial'\n\nexport interface AccumulativeShadowsProps {\n  /** Whether shadow creation only happens once (resets after props change), false */\n  once?: boolean\n  /** Whether shadows accumulate progressively over several frames, true */\n  accumulate?: boolean\n  /**\n   * Number of frames to render. More yields cleaner results but takes more time.\n   * If `accumulate && once`, 1 frame will be consumed every update for `frames` updates.\n   * Otherwise, `frames` frames are consumed for every update.\n   * 40\n   */\n  frames?: number\n  /** If `accumulate`, controls the refresh ratio, 100 */\n  blend?: number\n  /** If less than `Infinity`, limits the amount of frames rendered. Use this to increase performance once a movable scene has settled, Infinity */\n  limit?: number\n  /** Scale of the plane, 10 */\n  scale?: number\n  /** Opacity of the plane, 1 */\n  opacity?: number\n  /** Discards alpha pixels, 0.65 */\n  alphaTest?: number\n  /** Shadow color, black */\n  color?: ColorRepresentation\n  /** Colorblend, amount of `color` in shadow, 0 is black, 2 */\n  colorBlend?: number\n  /** Buffer resolution, 1024 */\n  resolution?: number\n  /** Texture tonemapping, true */\n  toneMapped?: boolean\n}\n\ninterface SoftShadowMaterialProps {\n  map: Texture\n  color?: ColorRepresentation\n  alphaTest?: number\n  blend?: number\n}\n\nconst props = withDefaults(defineProps<AccumulativeShadowsProps>(), {\n  once: true,\n  accumulate: true,\n  frames: 40,\n  limit: Infinity,\n  blend: 20,\n  scale: 10,\n  opacity: 1,\n  alphaTest: 0.65,\n  color: 'black',\n  colorBlend: 2,\n  resolution: 1024,\n  toneMapped: true,\n})\n\nextend({ SoftShadowMaterial })\n\nconst { renderer, scene, camera, invalidate } = useTres()\nconst gOuter = shallowRef<Group>()\nconst gPlane = shallowRef<Mesh<PlaneGeometry, SoftShadowMaterialProps & ShaderMaterial>>(null!)\nconst gLights = shallowRef<Group>(new Group())\nconst progressiveLightMap = computed(() => new ProgressiveLightMap(renderer as WebGLRenderer, scene.value, props.resolution))\nconst shadowMapTexture = shallowRef<Texture>()\n\nlet frameCount = 0\nlet frameLimitRemaining = props.limit\n\nfunction reset() {\n  // NOTE: Clear buffers, reset opacities, set frame count to 0\n  progressiveLightMap.value.clear()\n  if (gPlane.value) {\n    const material = gPlane.value.material\n    material.opacity = 0\n    material.alphaTest = 0\n  }\n  frameCount = 0\n  frameLimitRemaining = props.limit\n}\n\nfunction update(frames = 1) {\n  if (gPlane.value) {\n    const material = gPlane.value.material\n    if (props.accumulate) {\n      // NOTE: Adapt the opacity-blend ratio to the number of frames\n      material.opacity = Math.min(props.opacity, material.opacity + props.opacity / Math.max(2, props.blend))\n      material.alphaTest = Math.min(props.alphaTest, material.alphaTest + props.alphaTest / Math.max(2, props.blend))\n    }\n    else {\n      material.opacity = props.opacity\n      material.alphaTest = props.alphaTest\n    }\n  }\n\n  // NOTE: Switch accumulative lights on\n  gLights.value.visible = true\n  // NOTE: Collect scene lights and meshes\n  progressiveLightMap.value.prepare()\n\n  // NOTE: Update the lightmap and the accumulative lights\n  for (let i = 0; i < frames; i++) {\n    gLights.value?.children.forEach((light) => {\n      if ('update' in light && typeof light.update === 'function') {\n        light.update()\n      }\n    })\n    if (camera.value) {\n      const blend = Math.max(2, props.accumulate ? props.blend : props.frames)\n      progressiveLightMap.value.update(camera.value, blend)\n    }\n  }\n\n  // NOTE: Switch accumulative lights off\n  gLights.value.visible = false\n\n  // NOTE: Restore lights and meshes\n  progressiveLightMap.value.finish()\n\n  shadowMapTexture.value = progressiveLightMap.value.progressiveLightMap2.texture\n}\n\nwatchEffect(() => {\n  if (gPlane.value) { progressiveLightMap.value.configure(gPlane.value, gLights.value) }\n})\n\nwatch(() => [props.frames, props.once, props.accumulate, props.scale, props.limit], reset)\nwatchEffect(reset)\n\nuseLoop().onBeforeRender(() => {\n  if (!props.once) { frameCount = 0 }\n\n  frameLimitRemaining--\n  if (frameLimitRemaining < 0) { return }\n\n  if (props.accumulate && props.once) {\n    if (frameCount < props.frames || frameCount < props.blend) {\n      invalidate()\n      update()\n      frameCount++\n    }\n  }\n  else {\n    invalidate()\n    if (frameCount < props.frames) {\n      update(props.frames - frameCount)\n      frameCount = props.frames\n    }\n  }\n})\n\nwatchEffect(() => gLights.value.traverse = () => null)\n\ndefineExpose({ instance: gOuter, update: () => { reset(); update() } })\n</script>\n\n<template>\n  <TresGroup ref=\"gOuter\">\n    <TresGroup ref=\"gLights\">\n      <slot>\n        <RandomizedLights\n          :ambient=\"0.25\"\n          :bias=\"0.001\"\n          :count=\"8\"\n          :intensity=\"Math.PI\"\n          :map-size=\"1024\"\n          :position=\"[5, 5, -10]\"\n          :radius=\"2\"\n        />\n      </slot>\n    </TresGroup>\n\n    <TresMesh ref=\"gPlane\" :receive-shadow=\"true\" :scale=\"scale\" :rotation=\"[-Math.PI / 2, 0, 0]\">\n      <TresPlaneGeometry />\n      <TresSoftShadowMaterial\n        :alpha-test=\"alphaTest\"\n        :blend=\"colorBlend\"\n        :color=\"color\"\n        :depth-write=\"false\"\n        :map=\"shadowMapTexture\"\n        :opacity=\"opacity\"\n        :tone-mapped=\"toneMapped\"\n        :transparent=\"true\"\n      />\n    </TresMesh>\n  </TresGroup>\n</template>\n"
  },
  {
    "path": "src/core/staging/Align.vue",
    "content": "<script setup lang=\"ts\">\nimport { useLoop } from '@tresjs/core'\nimport type { Group, Object3D, Object3DEventMap } from 'three'\nimport { Box3, Sphere, Vector3 } from 'three'\nimport type { MaybeRefOrGetter } from 'vue'\nimport { shallowRef, toValue, watchEffect } from 'vue'\n\n// NOTE: Sources\n// https://github.com/pmndrs/drei/blob/master/src/core/Center.tsx\n\nexport interface AlignCallbackOptions {\n  /** The next parent above <Align /> */\n  parent: Object3D<Object3DEventMap>\n  /** The outmost container group of the <Align/> component */\n  container: Group\n  width: number\n  height: number\n  depth: number\n  boundingBox: Box3\n  boundingSphere: Sphere\n  center: Vector3\n  verticalAlignment: number\n  horizontalAlignment: number\n  depthAlignment: number\n}\n\nexport interface AlignProps {\n  top?: boolean\n  right?: boolean\n  bottom?: boolean\n  left?: boolean\n  front?: boolean\n  back?: boolean\n  /** Disable all axes */\n  disable?: boolean\n  /** Disable x-axis alignment */\n  disableX?: boolean\n  /** Disable y-axis alignment */\n  disableY?: boolean\n  /** Disable z-axis alignment */\n  disableZ?: boolean\n  /** See https://threejs.org/docs/index.html?q=box3#api/en/math/Box3.setFromObject */\n  precise?: boolean\n  /** Optional cacheKey to keep the component from recalculating on every render */\n  cacheKey?: MaybeRefOrGetter<any>\n}\n\nconst props = withDefaults(defineProps<AlignProps>(), {\n  precise: true,\n  cacheKey: undefined,\n})\n\nconst emit = defineEmits<{\n  (e: 'update' | 'change', props: AlignCallbackOptions): void\n}>()\n\nconst ref = shallowRef<Group>()\nconst outer = shallowRef<Group>()\nconst inner = shallowRef<Group>()\n\nconst box3 = new Box3()\nconst center = new Vector3()\nconst sphere = new Sphere()\n\nconst previous = { width: 0, height: 0, depth: 0, position: new Vector3() }\n\nfunction update() {\n  if (!outer.value || !inner.value || !ref.value) { return }\n  outer.value.matrixWorld.identity()\n  box3.setFromObject(inner.value, props.precise)\n  const width = box3.max.x - box3.min.x\n  const height = box3.max.y - box3.min.y\n  const depth = box3.max.z - box3.min.z\n  box3.getCenter(center)\n  box3.getBoundingSphere(sphere)\n  const yAlign = props.top ? height / 2 : props.bottom ? -height / 2 : 0\n  const xAlign = props.left ? -width / 2 : props.right ? width / 2 : 0\n  const zAlign = props.front ? depth / 2 : props.back ? -depth / 2 : 0\n\n  outer.value.position.set(\n    props.disable || props.disableX ? 0 : -center.x + xAlign,\n    props.disable || props.disableY ? 0 : -center.y + yAlign,\n    props.disable || props.disableZ ? 0 : -center.z + zAlign,\n  )\n\n  if (previous.width !== width\n    || previous.height !== height\n    || previous.depth !== depth\n    || !outer.value.position.equals(previous.position)) {\n    emit('change', {\n      parent: ref.value.parent! as Object3D<Object3DEventMap>,\n      container: ref.value,\n      width,\n      height,\n      depth,\n      boundingBox: box3,\n      boundingSphere: sphere,\n      center,\n      verticalAlignment: yAlign,\n      horizontalAlignment: xAlign,\n      depthAlignment: zAlign,\n    })\n    previous.width = width\n    previous.height = height\n    previous.depth = depth\n    previous.position.copy(outer.value.position)\n  }\n}\n\nlet off: (() => void) | null = null\nlet cacheKey: any = null\n\n// NOTE: `useLoop` requires TresContext, which is only\n// availble in setup. We need a handle in useEffect,\n// so keep a reference.\nconst loop = useLoop()\n\nwatchEffect(() => {\n  // NOTE: update whenever cachekey changes.\n\n  // NOTE: We might already always be updating, so `off`.\n  off?.()\n  off = null\n\n  // NOTE: Don't update if we resolve to the previous cacheKey value,\n  // unless cacheKey is null or undefined.\n  const nextKey = toValue(props.cacheKey)\n  if (nextKey === cacheKey && cacheKey !== null && cacheKey !== undefined) { return }\n  cacheKey = nextKey\n\n  if (props.cacheKey === null || props.cacheKey === undefined) {\n    off = loop.onBeforeRender(() => {\n      update()\n    }).off\n  }\n  else {\n    update()\n  }\n})\n\ndefineExpose({ instance: ref, update })\n</script>\n\n<template>\n  <TresGroup ref=\"ref\">\n    <TresGroup ref=\"outer\">\n      <TresGroup ref=\"inner\">\n        <slot></slot>\n      </TresGroup>\n    </TresGroup>\n  </TresGroup>\n</template>\n"
  },
  {
    "path": "src/core/staging/Backdrop.vue",
    "content": "<script setup lang=\"ts\">\nimport { ref, shallowRef, toRefs, watch } from 'vue'\nimport type { BufferAttribute, PlaneGeometry } from 'three'\nimport type { Ref } from 'vue'\n\nexport interface BackdropProps {\n  floor?: number\n  segments?: number\n  receiveShadow?: boolean\n}\n\nconst props = withDefaults(defineProps<BackdropProps>(), {\n  floor: 0.25,\n  segments: 20,\n  receiveShadow: false,\n})\n\nconst easeInExpo = (x: number) => (x === 0 ? 0 : 2 ** (10 * x - 10))\n\nconst { floor, segments, receiveShadow } = toRefs(props)\n\nconst planeRef: Ref<PlaneGeometry | null> = ref(null)\n\nwatch(\n  [segments, floor, planeRef],\n  ([segments, floor, planeRef]) => {\n    if (!planeRef || segments === null) { return }\n    let i = 0\n    const offset = segments / segments / 2\n    const position = planeRef.attributes.position as BufferAttribute\n    for (let x = 0; x < segments + 1; x++) {\n      for (let y = 0; y < segments + 1; y++) {\n        position.setXYZ(\n          i++,\n          x / segments - offset + (x === 0 ? -floor : 0),\n          y / segments - offset,\n          easeInExpo(x / segments),\n        )\n      }\n    }\n    position.needsUpdate = true\n    planeRef.computeVertexNormals()\n  },\n)\n\nconst backdropRef = shallowRef()\ndefineExpose({ instance: backdropRef })\n</script>\n\n<template>\n  <TresGroup\n    ref=\"backdropRef\"\n    v-bind=\"$attrs\"\n  >\n    <TresMesh\n      :receive-shadow=\"receiveShadow\"\n      :rotation=\"[-Math.PI / 2, 0, Math.PI / 2]\"\n    >\n      <TresPlaneGeometry\n        ref=\"planeRef\"\n        :args=\"[1, 1, segments, segments]\"\n      />\n      <slot>\n        <TresMeshStandardMaterial\n          :color=\"0x808080\"\n          :side=\"2\"\n        />\n      </slot>\n    </TresMesh>\n  </TresGroup>\n</template>\n"
  },
  {
    "path": "src/core/staging/Bounds/Bounds.ts",
    "content": "import type { VectorFlexibleParams } from '@tresjs/core'\nimport { normalizeVectorFlexibleParam } from '@tresjs/core'\nimport type { Camera, OrthographicCamera, PerspectiveCamera } from 'three'\nimport { Box3, MathUtils, Matrix4, Object3D, Quaternion, Vector3 } from 'three'\n\ninterface SizeReturn {\n  box: Box3\n  size: Vector3\n  center: Vector3\n  distance: number\n}\n\nexport interface BoundsControlsProto {\n  update: () => void\n  target: Vector3\n  maxDistance: number\n  addEventListener: (event: string, callback: (event: any) => void) => void\n  removeEventListener: (event: string, callback: (event: any) => void) => void\n}\n\ninterface StartT {\n  position: Vector3\n  quaternion: Quaternion\n  zoom: number\n}\n\ninterface GoalT {\n  position: Vector3 | undefined\n  quaternion: Quaternion | undefined\n  zoom: number | undefined\n  up: Vector3 | undefined\n  lookAt: Vector3 | undefined\n  box: Box3 | undefined\n  object: Box3 | Object3D | undefined\n}\n\nexport interface OnLookAtCallbackArg {\n  position: Vector3\n  quaternion: Quaternion\n  zoom: number | undefined\n  up: Vector3 | undefined\n  lookAt: Vector3\n  box: Box3\n  object: Box3 | Object3D | undefined\n}\n\ntype CachedFitArgs =\n  [ Vector3 | null, Vector3, Vector3 ]\n  | [ Vector3 | null, Vector3]\n  | [ Vector3 | null]\n  | [ Object3D ]\n  | [ Object3D, Vector3 ]\n  | [ Box3 ]\n  | [ Box3, Vector3 ]\n\nenum AnimationState {\n  NONE = 0,\n  ACTIVE = 2,\n}\n\nconst isOrthographicCamera = (def: Camera): def is OrthographicCamera =>\n  def && (def as OrthographicCamera).isOrthographicCamera\nconst isPerspectiveCamera = (def: Camera): def is PerspectiveCamera =>\n  def && (def as PerspectiveCamera).isPerspectiveCamera\nconst isBox3 = (def: any): def is Box3 => def && (def as Box3).isBox3\n\nconst easingFnDefault = (t: number) => { return 1 - Math.exp(-5 * t) + 0.007 * t }\n\nexport class Bounds extends Object3D {\n  camera: Camera\n  offset = 0.2\n  duration = 1\n  clip = true\n\n  private _start: StartT = {\n    position: new Vector3(),\n    quaternion: new Quaternion(),\n    zoom: 1,\n  }\n\n  private _goal: GoalT = {\n    position: undefined,\n    quaternion: undefined,\n    zoom: undefined,\n    up: undefined,\n    lookAt: undefined,\n    box: undefined,\n    object: undefined,\n  }\n\n  private _animationState = AnimationState.NONE\n  private _t = 0.0\n  private _controls: BoundsControlsProto | null = null\n  private _controlsRemoveEventListener = () => {}\n\n  // NOTE: Overloaded functions and TS `Parameters` does not work.\n  // moz-extension://b37b5993-6262-452a-b49a-4f9e44f44989/confirm-page.html?url=https%3A%2F%2Fgithub.com%2Fmicrosoft%2FTypeScript%2Fissues%2F29732&cookieStoreId=firefox-container-21&currentCookieStoreId=firefox-container-8\n  private _cachedFitArgs: CachedFitArgs = [this]\n\n  constructor(camera: Camera) {\n    super()\n    this.camera = camera\n  }\n\n  dispose() {\n    this.controls = null\n  }\n\n  onStart(_: OnLookAtCallbackArg) {}\n  onCancel(_: OnLookAtCallbackArg) {}\n  onEnd(_: OnLookAtCallbackArg) {}\n  easing = easingFnDefault\n\n  get controls() {\n    return this._controls\n  }\n\n  set controls(controls: BoundsControlsProto | null) {\n    this._controlsRemoveEventListener()\n    this._controlsRemoveEventListener = () => {}\n\n    if (controls) {\n      this._controls = controls\n      // NOTE: Try to prevent drag hijacking\n      // Attach an event to listen to `controls` \"start\".\n      // It is triggered when active controls are interacted with and\n      // should cancel animations here.\n      // https://threejs.org/docs/#examples/en/controls/OrbitControls\n      const callback = () => {\n        if (controls && this._goal.lookAt && this._animationState !== AnimationState.NONE) {\n          const front = new Vector3().setFromMatrixColumn(this.camera.matrix, 2)\n          const d0 = this._start.position.distanceTo(controls.target)\n          const d1 = (this._goal.position || this._start.position).distanceTo(this._goal.lookAt)\n          const d = (1 - this._t) * d0 + this._t * d1\n\n          controls.target.copy(this.camera.position).addScaledVector(front, -d)\n          controls.update()\n          this._stop()\n        }\n\n        this._animationState = AnimationState.NONE\n      }\n\n      controls.addEventListener('start', callback)\n\n      this._controlsRemoveEventListener = () => controls.removeEventListener('start', callback)\n    }\n  }\n\n  private _stop() {\n    if (this._goal.position) {\n      this.onCancel(this._goal as OnLookAtCallbackArg)\n    }\n    _resetGoal(this._goal)\n  }\n\n  /**\n   * Calculates a boundary box around an `Object3D` and centers the camera accordingly.\n   */\n  lookAt(object: Object3D): void\n  /**\n   * Calculates a boundary box around an `Object3D` and centers the camera accordingly and animates the camera's `up` vector.\n   */\n  lookAt(object: Object3D, up: VectorFlexibleParams): void\n  /**\n   * Centers the camera's viewport on a `Box3`.\n   */\n  lookAt(box3: Box3): void\n  /**\n   * Centers the camera's viewport on a `Box3` and animates the camera's `up` vector.\n   */\n  lookAt(box3: Box3, up: VectorFlexibleParams): void\n  /**\n   * Look at a `Vector3`.\n   */\n  lookAt(target: VectorFlexibleParams): void\n  /**\n   * Look at a `Vector3`, if provided. Move the camera to `position`.\n   */\n  lookAt(target: VectorFlexibleParams | undefined | null, position: VectorFlexibleParams): void\n  /**\n   * Look at a `Vector3`, if provided. Move the camera to `position` and animate the camera's `up` vector.\n   */\n  lookAt(target: VectorFlexibleParams | undefined | null, position: VectorFlexibleParams, up: VectorFlexibleParams): void\n  /**\n   * Rerun `lookAt` using the prior arguments. If `lookAt` has never been called, uses the `Bounds` object.\n   */\n  lookAt(): void\n  lookAt(\n    arg0?: Object3D | Box3 | VectorFlexibleParams | undefined | null,\n    arg1?: VectorFlexibleParams,\n    arg2?: VectorFlexibleParams,\n  ) {\n    // NOTE: Normalize args\n    const size = arguments.length\n\n    let args: CachedFitArgs = this._cachedFitArgs\n    const v1 = arg1 ? new Vector3().fromArray(normalizeVectorFlexibleParam(arg1)) : new Vector3()\n    const v2 = arg2 ? new Vector3().fromArray(normalizeVectorFlexibleParam(arg2)) : new Vector3()\n\n    if (size === 0) {\n      // NOTE: We didn't get any args, use prior args.\n      args = this._cachedFitArgs\n    }\n    else if (!arg0 && arg0 !== 0) {\n      // NOTE: `fit(lookAt=undefined | null)`\n      if (size === 1) { args = [null] }\n      // NOTE: `fit(lookAt=undefined | null, lookAt: VectorFlexibleParams)`\n      else if (size === 2) { args = [null, v1] }\n      // NOTE: `fit(lookAt=undefined | null, lookAt: VectorFlexibleParams, up: VectorFlexibleParams)`\n      else if (size === 3) { args = [null, v1, v2] }\n    }\n    else if (typeof arg0 === 'number' || (arg0 as Vector3).isVector3 || Array.isArray(arg0)) {\n      const v0 = new Vector3().fromArray(normalizeVectorFlexibleParam(arg0 as VectorFlexibleParams))\n      // NOTE: `fit(position: VectorFlexibleParams)`\n      if (size === 1) { args = [v0] }\n      // NOTE: `fit(position: VectorFlexibleParams, lookAt: VectorFlexibleParams)`\n      else if (size === 2) { args = [v0, v1] }\n      // NOTE: `fit(position: VectorFlexibleParams, lookAt: VectorFlexibleParams, up: VectorFlexibleParams)`\n      else if (size === 3) { args = [v0, v1, v2] }\n    }\n    else if ((arg0 as Box3).isBox3) {\n      // NOTE: `fit(box3: Box3)`\n      if (size === 1) { args = [arg0 as Box3] }\n      // NOTE: `fit(box3: Box3, up)`\n      else { args = [arg0 as Box3, arg1 as Vector3] }\n    }\n    else if ((arg0 as Object3D).isObject3D) {\n      // NOTE: `fit(object: Object3D)`\n      if (size === 1) { args = [arg0 as Object3D] }\n      // NOTE: `fit(object: Object3D, up)`\n      else { args = [arg0 as Object3D, arg1 as Vector3] }\n    }\n\n    // NOTE: End normalization.\n\n    this._cachedFitArgs = args\n\n    this._stop()\n    _resetGoal(this._goal)\n\n    if (args.length > 0 && (args[0] === null || args[0] === undefined || (args[0] as Vector3).isVector3)) {\n      // NOTE: The user sent specific numeric values, not an object.\n      const [lookAt, position, up] = args\n      this._start.position.copy(this.camera.position)\n      this._start.quaternion.copy(this.camera.quaternion)\n      isOrthographicCamera(this.camera) && (this._start.zoom = (this.camera as OrthographicCamera).zoom)\n\n      if (position) {\n        this._goal.position = Array.isArray(position) ? new Vector3(...position) : (position as Vector3).clone()\n      }\n      else {\n        this._goal.position = this.camera.position\n      }\n\n      if (lookAt) {\n        this._goal.lookAt = Array.isArray(lookAt) ? new Vector3(...lookAt) : (lookAt as Vector3).clone()\n      }\n      else {\n        this._goal.lookAt = new Vector3(0, 0, 1).applyQuaternion(this.camera.quaternion)\n      }\n\n      if (up) {\n        this._goal.up = Array.isArray(up) ? new Vector3(...up) : up.clone()\n      }\n\n      const mCamRot = new Matrix4().lookAt(\n        this._goal.position || this.camera.position,\n        this._goal.lookAt,\n        this._goal.up ?? this.camera.up,\n      )\n      this._goal.quaternion = new Quaternion().setFromRotationMatrix(mCamRot)\n    }\n    else {\n      const box3OrObject = args[0] as Box3 | Object3D\n      const { center, distance, box } = _getSize(box3OrObject, this.camera, this.offset)\n\n      this._start.position.copy(this.camera.position)\n      this._start.quaternion.copy(this.camera.quaternion)\n      isOrthographicCamera(this.camera) && (this._start.zoom = (this.camera as OrthographicCamera).zoom)\n\n      const direction = this.camera.position.clone().sub(center).normalize()\n      this._goal.object = box3OrObject\n      this._goal.box = box\n      this._goal.position = center.clone().addScaledVector(direction, distance)\n      this._goal.lookAt = center.clone()\n      const mCamRot = new Matrix4().lookAt(this._goal.position, this._goal.lookAt, this.camera.up)\n      this._goal.quaternion = new Quaternion().setFromRotationMatrix(mCamRot)\n\n      if (isOrthographicCamera(this.camera)) {\n        let maxHeight = 0\n        let maxWidth = 0\n        const vertices = [\n          new Vector3(box.min.x, box.min.y, box.min.z),\n          new Vector3(box.min.x, box.max.y, box.min.z),\n          new Vector3(box.min.x, box.min.y, box.max.z),\n          new Vector3(box.min.x, box.max.y, box.max.z),\n          new Vector3(box.max.x, box.max.y, box.max.z),\n          new Vector3(box.max.x, box.max.y, box.min.z),\n          new Vector3(box.max.x, box.min.y, box.max.z),\n          new Vector3(box.max.x, box.min.y, box.min.z),\n        ]\n\n        // NOTE: Transform the center and each corner to camera space\n        const goal = this._goal\n        const pos = goal.position || this.camera.position\n        const target = goal.lookAt || this._controls?.target\n        const up = goal.up || this.camera.up\n        const mCamWInv = target\n          ? new Matrix4().lookAt(pos, target, up).setPosition(pos).invert()\n          : this.camera.matrixWorldInverse\n        for (const v of vertices) {\n          v.applyMatrix4(mCamWInv)\n          maxHeight = Math.max(maxHeight, Math.abs(v.y))\n          maxWidth = Math.max(maxWidth, Math.abs(v.x))\n        }\n        maxHeight *= 2\n        maxWidth *= 2\n        const zoomForHeight = (this.camera.top - this.camera.bottom) / maxHeight\n        const zoomForWidth = (this.camera.right - this.camera.left) / maxWidth\n\n        goal.zoom = Math.min(zoomForHeight, zoomForWidth) / (1 + this.offset)\n        // NOTE: Fix possible division by 0.\n        if (Number.isNaN(goal.zoom)) { goal.zoom = 0 }\n      }\n\n      if (this.clip) {\n        if (isPerspectiveCamera(this.camera)) {\n          this.camera.near = Math.abs(distance) / 100\n          this.camera.far = Math.abs(distance) * 100\n          this.camera.updateProjectionMatrix()\n        }\n\n        if (this._controls) {\n          this._controls.maxDistance = Math.abs(distance) * 100\n          this._controls.update()\n        }\n      }\n    }\n\n    this._t = 0\n    this._animationState = AnimationState.ACTIVE\n\n    this.onStart && this.onStart(this._goal as OnLookAtCallbackArg)\n  }\n\n  animate(delta: number) {\n    if (this._animationState === AnimationState.NONE) {\n      return false\n    }\n\n    if (this._animationState === AnimationState.ACTIVE) {\n      this._t += delta / this.duration\n      this._t = MathUtils.clamp(this._t, 0, 1)\n\n      if (this._t >= 1) {\n        this._goal.position && this.camera.position.copy(this._goal.position)\n        this._goal.quaternion && this.camera.quaternion.copy(this._goal.quaternion)\n        this._goal.up && this.camera.up.copy(this._goal.up)\n        this._goal.zoom && isOrthographicCamera(this.camera) && (this.camera.zoom = this._goal.zoom)\n\n        this.camera.updateMatrixWorld()\n        if (isPerspectiveCamera(this.camera)) {\n          this.camera.updateProjectionMatrix()\n        }\n\n        if (this._controls && this._goal.lookAt) {\n          this._controls.target.copy(this._goal.lookAt)\n          this._controls.update()\n        }\n\n        this._animationState = AnimationState.NONE\n        this.onEnd && this.onEnd(this._goal as OnLookAtCallbackArg)\n        _resetGoal(this._goal)\n      }\n      else {\n        const k = this.easing && this.easing(this._t)\n\n        this._goal.position && this.camera.position.lerpVectors(this._start.position, this._goal.position, k)\n        this._goal.quaternion && this.camera.quaternion.slerpQuaternions(this._start.quaternion, this._goal.quaternion, k)\n        this._goal.up && this.camera.up.set(0, 1, 0).applyQuaternion(this.camera.quaternion)\n        this._goal.zoom\n        && isOrthographicCamera(this.camera)\n        && (this.camera.zoom = (1 - k) * this._start.zoom + k * this._goal.zoom)\n\n        this.camera.updateMatrixWorld()\n        if (isPerspectiveCamera(this.camera)) {\n          this.camera.updateProjectionMatrix()\n        }\n      }\n    }\n\n    return true\n  }\n}\n\nfunction _getSize(box3OrObject: Box3 | Object3D, camera: Camera, offset = 0): SizeReturn {\n  const box = new Box3()\n  if (isBox3(box3OrObject)) {\n    box.copy(box3OrObject)\n  }\n  else {\n    box3OrObject.updateWorldMatrix(true, true)\n    box.setFromObject(box3OrObject)\n  }\n\n  if (box.isEmpty()) {\n    const max = camera.position.length() || 10\n    box.setFromCenterAndSize(new Vector3(), new Vector3(max, max, max))\n  }\n\n  const boxSize = box.getSize(new Vector3())\n  const center = box.getCenter(new Vector3())\n  const maxSize = Math.max(boxSize.x, boxSize.y, boxSize.z)\n  const fitHeightDistance = isOrthographicCamera(camera)\n    ? maxSize * 4\n    : maxSize / (2 * Math.atan((Math.PI * (camera as PerspectiveCamera).fov) / 360))\n  const fitWidthDistance = isOrthographicCamera(camera) ? maxSize * 4 : fitHeightDistance / (camera as PerspectiveCamera).aspect\n  const distance = (1 + offset) * Math.max(fitHeightDistance, fitWidthDistance)\n\n  return { box, size: boxSize, center, distance }\n}\n\nfunction _resetGoal(goal: GoalT) {\n  goal.position = undefined\n  goal.quaternion = undefined\n  goal.zoom = undefined\n  goal.up = undefined\n  goal.lookAt = undefined\n  goal.box = undefined\n  goal.object = undefined\n}\n"
  },
  {
    "path": "src/core/staging/Bounds/component.vue",
    "content": "<script setup lang=\"ts\">\nimport { computed, onMounted, onUnmounted, watch, watchEffect } from 'vue'\nimport type { BoundsControlsProto, OnLookAtCallbackArg } from './Bounds'\nimport { Bounds } from './Bounds'\nimport { useLoop, useTres } from '@tresjs/core'\nimport { PerspectiveCamera } from 'three'\nimport { useDebounceFn } from '@vueuse/core'\n\nexport interface BoundsProps {\n  /**\n   * Duration of the `lookAt` animation in seconds, 1.0\n   */\n  duration?: number\n  /**\n   * Additional distance from the target when using `lookAt` with a `Box3` or `Object3D`, 0.2\n   */\n  offset?: number\n  /**\n   * Whether to re`lookAt` the last target when the screen is resized, false\n   */\n  useResize?: boolean\n  /**\n   * Whether to `lookAt` the `Bounds` object when the component is mounts, false\n   */\n  useMounted?: boolean\n  /**\n   * Whether to adjust the camera's `near` and `far` settings when using `lookAt`, false\n   */\n  clip?: boolean\n  /**\n   * Animation's easing function. `t` and the returned value should be in the interval `[0, 1]`, cubicEaseOut\n   */\n  easing?: (t: number) => number\n}\n\nconst props = withDefaults(defineProps<BoundsProps>(), {\n  duration: 1.0,\n  offset: 0.2,\n  useResize: false,\n  useMounted: false,\n  clip: false,\n})\n\nconst emit = defineEmits<{\n  (e: 'start', sizeProps: OnLookAtCallbackArg): void\n  (e: 'cancel', sizeProps: OnLookAtCallbackArg): void\n  (e: 'end', sizeProps: OnLookAtCallbackArg): void\n}>()\n\nconst { camera, controls, sizes: size, invalidate } = useTres()\nconst defaultEasing = (t: number) => 1 - (1 - t) ** 3\n\nconst bounds = new Bounds(camera.value ?? new PerspectiveCamera())\nbounds.easing = props.easing ?? defaultEasing\nbounds.onStart = (arg: OnLookAtCallbackArg) => emit('start', arg)\nbounds.onCancel = (arg: OnLookAtCallbackArg) => emit('cancel', arg)\nbounds.onEnd = (arg: OnLookAtCallbackArg) => emit('end', arg)\n\nconst refresh = () => {\n  bounds.offset = props.offset\n  bounds.duration = props.duration\n  bounds.clip = props.clip\n  bounds.lookAt()\n  invalidate()\n}\n\nuseLoop().onBeforeRender(({ delta }) => {\n  if (bounds.animate(delta)) {\n    invalidate()\n  }\n})\n\nwatchEffect(() => {\n  if (controls.value) { bounds.controls = controls.value as unknown as BoundsControlsProto }\n})\n\nconst shallowCam = computed(() => camera.value?.uuid)\nwatch(shallowCam, () => {\n  if (camera.value) { bounds.camera = camera.value }\n}, { immediate: true, deep: false })\n\nconst refreshDebounce = useDebounceFn(refresh, 250, { maxWait: 2000 })\n\nwatch(() => [size.width.value, size.height.value], () => {\n  if (props.useResize) { refreshDebounce() }\n})\n\n// NOTE: Tres core doesn't currently allow for most\n// callback props to declaratively redefine methods.\n// (Most method props will be called instead.)\n// So we need to watch and update here.\nwatch(() => [props.easing], () => {\n  bounds.easing = props.easing ?? defaultEasing\n}, { immediate: true })\n\nonMounted(() => { if (props.useMounted) { refreshDebounce() } })\nonUnmounted(() => bounds.dispose())\ndefineExpose({ instance: bounds })\n</script>\n\n<template>\n  <primitive\n    :object=\"bounds\"\n    :duration=\"duration\"\n    :offset=\"offset\"\n  >\n    <slot></slot>\n  </primitive>\n</template>\n"
  },
  {
    "path": "src/core/staging/CircleShadow.vue",
    "content": "<script setup lang=\"ts\">\nimport { Color, DoubleSide, Texture } from 'three'\n\nimport { onUnmounted, shallowRef, watchEffect } from 'vue'\n\ninterface ShadowProps {\n  color?: Color | number | string\n  offset?: number\n  opacity?: number\n  fog?: boolean\n  depthWrite?: boolean\n}\n\nconst props = withDefaults(defineProps<ShadowProps>(), {\n  color: 'black',\n  offset: 0.0,\n  opacity: 0.5,\n  fog: false,\n  depthWrite: false,\n})\n\nconst SIZE = 128\nconst canvas = document.createElement('canvas')\ncanvas.width = SIZE\ncanvas.height = SIZE\nconst context = canvas.getContext('2d') as CanvasRenderingContext2D\n\nconst texture = new Texture(canvas)\n\nfunction createCanvas() {\n  const gradient = context.createRadialGradient(\n    canvas.width / 2,\n    canvas.height / 2,\n    0,\n    canvas.width / 2,\n    canvas.height / 2,\n    canvas.width / 2,\n  )\n\n  gradient.addColorStop(props.offset, new Color(props.color).getStyle())\n  gradient.addColorStop(1, 'rgba(0,0,0,0)')\n  context.clearRect(0, 0, SIZE, SIZE)\n  context.fillStyle = gradient\n  context.fillRect(0, 0, canvas.width, canvas.height)\n\n  texture.needsUpdate = true\n}\n\nwatchEffect(createCanvas)\n\nconst shadowRef = shallowRef()\n\ndefineExpose({ instance: shadowRef })\n\nonUnmounted(() => texture.dispose())\n</script>\n\n<template>\n  <TresMesh ref=\"shadowRef\" :rotation-x=\"-Math.PI * 0.5\">\n    <TresPlaneGeometry />\n    <TresMeshBasicMaterial transparent :opacity=\"props.opacity\" :fog=\"props.fog\" :depth-write=\"depthWrite\" :side=\"DoubleSide\" :map=\"texture\" />\n  </TresMesh>\n</template>\n"
  },
  {
    "path": "src/core/staging/ContactShadows.vue",
    "content": "<script setup lang=\"ts\">\n// NOTE: The author of the original code is @mrdoob https://twitter.com/mrdoob\n// https://threejs.org/examples/?q=con#webgl_shadow_contact\n\n// NOTE: Shader inspiration taken from R3F/Drei:\n// https://github.com/pmndrs/drei/blob/b50a2d4b1a1278ae36058b9b53b85a00ef195762/src/core/ContactShadows.tsx#L10\n\nimport { useLoop } from '@tresjs/core'\nimport {\n  Color,\n  Group,\n  Mesh,\n  MeshBasicMaterial,\n  MeshDepthMaterial,\n  OrthographicCamera,\n  PlaneGeometry,\n  ShaderMaterial,\n  WebGLRenderTarget,\n} from 'three'\nimport { HorizontalBlurShader, VerticalBlurShader } from 'three-stdlib'\nimport { onUnmounted, toValue, watch } from 'vue'\nimport type { TresColor, TresRenderer } from '@tresjs/core'\nimport type {\n  ColorRepresentation,\n  Scene,\n} from 'three'\n\nexport interface ContactShadowsProps {\n  /**\n   * The opacity of the shadows.\n   *\n   * @default 1\n   * @type {number}\n   * @memberof ContactShadowsProps\n   *\n   */\n  opacity?: number\n  /**\n   * The blur of the shadows.\n   *\n   * @default 1\n   * @type {number}\n   * @memberof ContactShadowsProps\n   *\n   */\n  blur?: number\n  /**\n   * The color of the shadows.\n   *\n   * @default '#000000'\n   * @type {TresColor}\n   * @memberof ContactShadowsProps\n   *\n   */\n  color?: TresColor\n  /**\n   * The tint at the \"core\" of the shadows.\n   *\n   * @default undefined\n   * @type {TresColor}\n   * @memberof ContactShadowsProps\n   *\n   */\n  tint?: TresColor\n  /**\n   * The scale of the shadows.\n   */\n  scale?: number | [x: number, y: number]\n  /**\n   * The width of the shadow plane.\n   *\n   * @default 1\n   * @type {number}\n   * @memberof ContactShadowsProps\n   *\n   */\n  width?: number\n  /**\n   * The height of the shadow plane.\n   *\n   * @default 1\n   * @type {number}\n   * @memberof ContactShadowsProps\n   *\n   */\n  height?: number\n  /**\n   * How far the OrthographicCamera should be to capture the shadows.\n   *\n   * @default 10\n   * @type {number}\n   * @memberof ContactShadowsProps\n   *\n   */\n  far?: number\n  /**\n   * Whether the shadows should be smooth or not.\n   *\n   * @default true\n   * @type {boolean}\n   * @memberof ContactShadowsProps\n   *\n   */\n  smooth?: boolean\n  /**\n   * The resolution of the shadows.\n   *\n   * @default 512\n   * @type {number}\n   * @memberof ContactShadowsProps\n   *\n   */\n  resolution?: number\n  /**\n   * The number of frames to render the shadows.\n   *\n   * @default Infinity\n   * @type {number}\n   * @memberof ContactShadowsProps\n   *\n   */\n  frames?: number\n  /**\n   * Whether the shadows should write to the depth buffer or not.\n   *\n   * @default false\n   * @type {boolean}\n   * @memberof ContactShadowsProps\n   *\n   */\n  depthWrite?: boolean\n  /**\n   * Whether the shadows should write to the depth buffer or not.\n   *\n   * @default false\n   * @type {boolean}\n   * @memberof ContactShadowsProps\n   *\n   */\n}\n\nconst props = withDefaults(defineProps<ContactShadowsProps>(), {\n  opacity: 1,\n  blur: 1,\n  color: '#000000',\n  tint: undefined,\n  scale: 10,\n  width: 1,\n  height: 1,\n  far: 10,\n  smooth: true,\n  resolution: 512,\n  frames: Number.POSITIVE_INFINITY,\n  depthWrite: false,\n})\n\nfunction blurShadow(\n  blur: number,\n  renderer: TresRenderer,\n  pool: ReturnType<typeof init>,\n) {\n  pool.blurPlane.visible = true\n  pool.blurPlane.material = pool.horizontalBlurMaterial\n  pool.horizontalBlurMaterial.uniforms.tDiffuse.value = pool.renderTarget.texture\n  pool.horizontalBlurMaterial.uniforms.h.value = blur / 256\n\n  renderer.setRenderTarget(pool.renderTargetBlur)\n\n  renderer.render(pool.blurPlane, pool.shadowCamera)\n\n  pool.blurPlane.material = pool.verticalBlurMaterial\n  pool.verticalBlurMaterial.uniforms.tDiffuse.value = pool.renderTargetBlur.texture\n  pool.verticalBlurMaterial.uniforms.v.value = blur / 256\n\n  renderer.setRenderTarget(pool.renderTarget)\n\n  renderer.render(pool.blurPlane, pool.shadowCamera)\n\n  pool.blurPlane.visible = false\n}\n\nfunction update(\n  ps: typeof props,\n  scene: Scene,\n  renderer: TresRenderer,\n  pool: ReturnType<typeof init>,\n) {\n  const {\n    renderTarget,\n    shadowCamera,\n    depthMaterial,\n  } = pool\n  const initialBackground = scene.background\n  scene.background = null\n\n  // NOTE: Force the depthMaterial to everything\n  scene.overrideMaterial = depthMaterial\n\n  // NOTE: Set renderer clear alpha\n  const initialClearAlpha = renderer.getClearAlpha()\n  renderer.setClearAlpha(0)\n\n  // NOTE: Render to the render target to get the depths\n  renderer.setRenderTarget(renderTarget)\n  renderer.render(scene, shadowCamera)\n\n  // NOTE: Reset the override material\n  scene.overrideMaterial = null\n\n  blurShadow(ps.blur, renderer, pool)\n\n  // NOTE: A second pass to reduce the artifacts\n  // (0.4 is the minimum blur amount so that the artifacts are gone)\n  if (ps.smooth) {\n    blurShadow(ps.blur * 0.4, renderer, pool)\n  }\n\n  // NOTE: Reset and render the normal scene\n  renderer.setRenderTarget(null)\n  renderer.setClearAlpha(initialClearAlpha)\n  scene.background = initialBackground\n}\n\nfunction init(p: typeof props) {\n  const shadowGroup = new Group()\n\n  // NOTE: The render target that will show the shadows in the plane texture\n  const renderTarget = new WebGLRenderTarget(p.resolution, p.resolution)\n  renderTarget.texture.generateMipmaps = false\n\n  // NOTE: The render target that we will use to blur the first render target\n  const renderTargetBlur = new WebGLRenderTarget(p.resolution, p.resolution)\n  renderTargetBlur.texture.generateMipmaps = false\n\n  // NOTE: Make a plane and make it face up\n  const planeGeometry = new PlaneGeometry(p.width, p.height).rotateX(Math.PI / 2)\n  const planeMaterial = new MeshBasicMaterial({\n    map: renderTarget.texture,\n    opacity: p.opacity,\n    transparent: true,\n    depthWrite: p.depthWrite,\n    color: new Color((p.color as ColorRepresentation) ?? 'black'),\n  })\n  const plane = new Mesh(planeGeometry, planeMaterial)\n  shadowGroup.add(plane)\n\n  // NOTE: The y from the texture is flipped!\n  plane.scale.y = -1\n\n  // NOTE: The plane onto which to blur the texture\n  const blurPlane = new Mesh(planeGeometry)\n  blurPlane.visible = false\n  shadowGroup.add(blurPlane)\n\n  // NOTE: The camera to render the depth material from\n  const shadowCamera = new OrthographicCamera(-p.width / 2, p.width / 2, p.height / 2, -p.height / 2, 0, 0.3)\n  shadowCamera.rotation.x = Math.PI / 2 // get the camera to look up\n  shadowGroup.add(shadowCamera)\n\n  const depthMaterial = new MeshDepthMaterial()\n  const horizontalBlurMaterial = new ShaderMaterial(HorizontalBlurShader)\n  horizontalBlurMaterial.depthTest = false\n\n  const verticalBlurMaterial = new ShaderMaterial(VerticalBlurShader)\n  verticalBlurMaterial.depthTest = false\n\n  return {\n    renderTarget,\n    renderTargetBlur,\n    shadowCamera,\n    depthMaterial,\n    horizontalBlurMaterial,\n    verticalBlurMaterial,\n    shadowGroup,\n    plane,\n    blurPlane,\n  }\n};\n\nfunction setSize(ps: typeof props, pool: ReturnType<typeof init>) {\n  const shadowCamera = pool.shadowCamera\n  shadowCamera.left = -ps.width / 2\n  shadowCamera.right = ps.width / 2\n  shadowCamera.top = ps.height / 2\n  shadowCamera.bottom = -ps.height / 2\n  shadowCamera.far = ps.far\n\n  const w = ps.width * (Array.isArray(ps.scale) ? ps.scale[0] : (ps.scale || 1))\n  const h = ps.height * (Array.isArray(ps.scale) ? ps.scale[1] : (ps.scale || 1))\n  pool.shadowGroup.scale.set(w, ps.far, h)\n}\n\nfunction setResolution(resolution: number, pool: ReturnType<typeof init>) {\n  pool.renderTarget.dispose()\n  pool.renderTargetBlur.dispose()\n\n  pool.renderTarget = new WebGLRenderTarget(resolution, resolution)\n  pool.renderTarget.texture.generateMipmaps = false\n\n  pool.renderTargetBlur = new WebGLRenderTarget(resolution, resolution)\n  pool.renderTargetBlur.texture.generateMipmaps = false\n\n  pool.plane.material.map = pool.renderTarget.texture\n}\n\nfunction setColors(ps: typeof props, pool: ReturnType<typeof init>) {\n  pool.plane.material.color = new Color(ps.color as ColorRepresentation ?? 'black')\n\n  pool.depthMaterial.dispose()\n  pool.depthMaterial = new MeshDepthMaterial()\n  pool.depthMaterial.onBeforeCompile = function (shader) {\n    const tint = ps.tint ? new Color(ps.tint as ColorRepresentation) : new Color('white')\n    const { r, g, b } = tint\n    const fragmentShader = shader.fragmentShader.replace(\n      'gl_FragColor = vec4( vec3( 1.0 - fragCoordZ ), opacity );',\n      `gl_FragColor = vec4( ${r}, ${g}, ${b}, ( 1.0 - fragCoordZ ) * opacity);`,\n    )\n    shader.fragmentShader = fragmentShader\n  }\n}\n\nconst { onBeforeRender } = useLoop()\nconst pool = init(props)\n\nlet count = 0\nconst updateOnNextRender = () => count = count >= props.frames ? props.frames - 1 : count\nonBeforeRender(\n  ({ renderer, scene /* invalidate */ }) => {\n    if (count < props.frames) {\n      count++\n      update(props, toValue(scene), renderer, pool)\n      // TODO: comment this until invalidate is back in the loop callback on v5\n      // invalidate()\n    }\n  },\n)\n\nwatch(() => [props.opacity, props.depthWrite, props.blur, props.smooth], () => {\n  pool.plane.material.opacity = props.opacity ?? 1\n  pool.plane.material.depthWrite = props.depthWrite ?? false\n  updateOnNextRender()\n}, { immediate: true })\n\nwatch(() => [props.color, props.tint], () => {\n  setColors(props, pool)\n  updateOnNextRender()\n}, { immediate: true })\n\nwatch(() => [props.resolution], () => { setResolution(props.resolution, pool); updateOnNextRender() })\nwatch(() => [props.width, props.height, props.scale, props.far], () => { setSize(props, pool); updateOnNextRender() }, { immediate: true })\n\nonUnmounted(() => {\n  for (const obj of Object.values(pool)) {\n    if (obj && 'dispose' in obj && typeof obj.dispose === 'function') {\n      obj.dispose()\n    }\n  }\n})\n\ndefineExpose({ instance: pool.shadowGroup })\n</script>\n\n<template>\n  <primitive :object=\"pool.shadowGroup\" />\n</template>\n"
  },
  {
    "path": "src/core/staging/Fit.vue",
    "content": "<script setup lang=\"ts\">\nimport { useTres } from '@tresjs/core'\nimport { Box3, Group, Vector3 } from 'three'\nimport { nextTick, onMounted, shallowRef, watch } from 'vue'\nimport type { Object3D } from 'three'\n\nexport interface Props {\n  /**\n   * If `into` is:\n   * - omitted or explicitly `undefined`: position/scale children to fit into a 1 × 1 × 1 `Box3` at world origin.\n   * - `null`: turn off `<Fit />`; reset scale/position of children.\n   * - `number`: convert argument to `Vector3(number, number, number)`.\n   * - `[number, number, number]`: convert argument to `Vector3`.\n   * - `Vector3`: position/scale children to fit inside a `Box3` of size `Vector3` at target objects' cumulative center.\n   * - `Box3`: position/scale children to fit inside `Box3`.\n   * - `Object3D`: position/scale children to fit inside calculated `Box3`. [See `THREE.Box3.setFromObject`](https://threejs.org/docs/#api/en/math/Box3.setFromObject). `<Fit />` must not contain the `Object3D` and vice-versa.\n   */\n  into?: number | [number, number, number] | Vector3 | Box3 | Object3D | null\n  /** [See `precise` argument in `THREE.Box3.setFromObject`](https://threejs.org/docs/index.html?q=box3#api/en/math/Box3.setFromObject) */\n  precise?: boolean\n}\n\nconst props = withDefaults(\n  defineProps<Props>(),\n  {\n    into: () => new Box3(new Vector3(-0.5, -0.5, -0.5), new Vector3(0.5, 0.5, 0.5)),\n    precise: false,\n  },\n)\n\nconst { invalidate } = useTres()\n\nconst middle = shallowRef<Group>(new Group())\nconst inner = shallowRef<Group>(new Group())\n\ninterface IntoPropNormalized {\n  box3: Box3\n  use: { position: boolean }\n}\n\nfunction fit(container: typeof props.into, precise: typeof props.precise) {\n  // NOTE: Reset transforms on this\n  // component's THREE.Groups\n  middle.value.position.set(0, 0, 0)\n  middle.value.updateMatrixWorld()\n  inner.value.scale.set(1, 1, 1)\n  inner.value.updateMatrixWorld()\n\n  if (!inner.value.children.length || container === null) {\n    // NOTE: Nothing more to do.\n    // Return early to skip expensive measuring.\n    return\n  }\n\n  const { box3: containerBox, use } = normalizeContainer(container, precise)\n\n  const childBox = new Box3()\n  inner.value.children.forEach(c => childBox.expandByObject(c, precise))\n  const childBoxSize = childBox.getSize(new Vector3())\n  const containerBoxSize = containerBox.getSize(new Vector3())\n\n  // NOTE: To fit in the container, we need to calculate\n  // which dimension has the smallest scale, then apply\n  // it uniformly to all dimensions.\n  const scale = Math.min(\n    containerBoxSize.x / childBoxSize.x,\n    containerBoxSize.y / childBoxSize.y,\n    containerBoxSize.z / childBoxSize.z,\n  )\n  // NOTE: Handle possible prior division by 0 by checking for positive infinity.\n  inner.value.scale.setScalar(scale === Number.POSITIVE_INFINITY ? 1 : scale)\n  inner.value.updateMatrixWorld()\n\n  const childBoxCenter = middle.value.worldToLocal(childBox.getCenter(new Vector3()))\n\n  if (use.position) {\n    // NOTE: Move the scaled children so that they occupy the container.\n    const containerBoxCenter = middle.value.worldToLocal(containerBox.getCenter(new Vector3()))\n    middle.value.position.copy(containerBoxCenter.sub(childBoxCenter.multiplyScalar(scale)))\n  }\n  else {\n    // NOTE: Move the scaled children so that they appear to scale\n    // relative to the center of their bounding box (and not the origin\n    // of the \"inner\" THREE.Group).\n    middle.value.position.copy(childBoxCenter.sub(childBoxCenter.multiplyScalar(scale)))\n  }\n\n  invalidate()\n}\n\nfunction normalizeContainer(container: typeof props.into, precise: typeof props.precise): IntoPropNormalized {\n  if (typeof container === 'number') {\n    container = new Vector3(container, container, container)\n  }\n  else if (Array.isArray(container)) {\n    container = new Vector3(...container)\n  }\n\n  if (container && 'isVector3' in container && container.isVector3) {\n    return { box3: new Box3(new Vector3(0, 0, 0), container), use: { position: false } }\n  }\n  else if (container && 'isBox3' in container && container.isBox3) {\n    return { box3: container as Box3, use: { position: true } }\n  }\n  else if (container && 'isObject3D' in container && container.isObject3D) {\n    return { box3: new Box3().setFromObject(container as Object3D, precise ?? false), use: { position: true } }\n  }\n\n  return {\n    box3: new Box3(new Vector3(-0.5, -0.5, -0.5), new Vector3(0.5, 0.5, 0.5)),\n    use: { position: true },\n  }\n}\n\nwatch(() => [props.into, props.precise], () => fit(props.into, props.precise))\n\nonMounted(() => {\n  fit(props.into, props.precise)\n  // NOTE: Tres core doesn't appear to apply transformations (position, rotation, scale)\n  // immediately on newly created elements, so the child and container elements might\n  // not have their correct dimensions. So we'll `fit` again in a moment.\n  nextTick().then(() => {\n    fit(props.into, props.precise)\n  })\n})\n\nconst outer = shallowRef()\ndefineExpose({\n  instance: outer,\n  fit: (\n    into: typeof props.into = new Box3(new Vector3(-0.5, -0.5, -0.5), new Vector3(0.5, 0.5, 0.5)),\n    precise = false,\n  ) => { fit(into, precise) },\n  update: () => fit(props.into, props.precise),\n})\n</script>\n\n<template>\n  <TresGroup ref=\"outer\">\n    <TresGroup ref=\"middle\">\n      <TresGroup ref=\"inner\">\n        <slot></slot>\n      </TresGroup>\n    </TresGroup>\n  </TresGroup>\n</template>\n"
  },
  {
    "path": "src/core/staging/Grid.vue",
    "content": "<script setup lang=\"ts\">\nimport { shaderMaterial } from '../../utils/shaderMaterial'\nimport type { ColorRepresentation, PlaneGeometry, ShaderMaterial, Side, Uniform } from 'three'\nimport { BackSide, Color, Mesh, Plane, Vector3 } from 'three'\nimport { extend, useLoop } from '@tresjs/core'\nimport { shallowRef } from 'vue'\n\n/**\n       Based on\n      https://github.com/Fyrestar/THREE.InfiniteGridHelper by https://github.com/Fyrestar\n      and https://github.com/threlte/threlte/blob/main/packages/extras/src/lib/components/Grid/Grid.svelte\n      by https://github.com/grischaerbe and https://github.com/jerzakm\n*/\n\nexport interface GridMaterialType {\n  /** Cell size, default: 0.5 */\n  cellSize?: number\n  /** Cell thickness, default: 0.5 */\n  cellThickness?: number\n  /** Cell color, default: black */\n  cellColor?: ColorRepresentation\n  /** Section size, default: 1 */\n  sectionSize?: number\n  /** Section thickness, default: 1 */\n  sectionThickness?: number\n  /** Section color, default: #2080ff */\n  sectionColor?: ColorRepresentation\n  /** Follow camera, default: false */\n  followCamera?: boolean\n  /** Display the grid infinitely, default: false */\n  infiniteGrid?: boolean\n  /** Fade distance, default: 100 */\n  fadeDistance?: number\n  /** Fade strength, default: 1 */\n  fadeStrength?: number\n  /** Fade from camera (1) or origin (0), or somewhere in between, default: camera */\n  fadeFrom?: number\n  /** Material side, default: THREE.BackSide */\n  side?: Side\n}\n\nexport type GridProps = GridMaterialType & {\n  /** Default plane-geometry arguments */\n  args?: ConstructorParameters<typeof PlaneGeometry>\n}\n\nconst props = withDefaults(defineProps<GridProps>(), {\n  cellColor: '#000000',\n  sectionColor: '#0000ff',\n  cellSize: 0.5,\n  sectionSize: 1,\n  followCamera: false,\n  infiniteGrid: false,\n  fadeDistance: 100,\n  fadeStrength: 1,\n  fadeFrom: 1,\n  cellThickness: 0.5,\n  sectionThickness: 1,\n  side: BackSide,\n})\n\nconst GridMaterial = shaderMaterial(\n  {\n    cellSize: 0.5,\n    sectionSize: 1,\n    fadeDistance: 100,\n    fadeStrength: 1,\n    fadeFrom: 1,\n    cellThickness: 0.5,\n    sectionThickness: 1,\n    cellColor: new Color(),\n    sectionColor: new Color(),\n    infiniteGrid: false,\n    followCamera: false,\n    worldCamProjPosition: new Vector3(),\n    worldPlanePosition: new Vector3(),\n  },\n  /* glsl */ `\n    varying vec3 localPosition;\n    varying vec4 worldPosition;\n\n    uniform vec3 worldCamProjPosition;\n    uniform vec3 worldPlanePosition;\n    uniform float fadeDistance;\n    uniform bool infiniteGrid;\n    uniform bool followCamera;\n\n    void main() {\n      localPosition = position.xzy;\n      if (infiniteGrid) localPosition *= 1.0 + fadeDistance;\n      \n      worldPosition = modelMatrix * vec4(localPosition, 1.0);\n      if (followCamera) {\n        worldPosition.xyz += (worldCamProjPosition - worldPlanePosition);\n        localPosition = (inverse(modelMatrix) * worldPosition).xyz;\n      }\n\n      gl_Position = projectionMatrix * viewMatrix * worldPosition;\n    }\n  `,\n  /* glsl */ `\n    varying vec3 localPosition;\n    varying vec4 worldPosition;\n\n    uniform vec3 worldCamProjPosition;\n    uniform float cellSize;\n    uniform float sectionSize;\n    uniform vec3 cellColor;\n    uniform vec3 sectionColor;\n    uniform float fadeDistance;\n    uniform float fadeStrength;\n    uniform float fadeFrom;\n    uniform float cellThickness;\n    uniform float sectionThickness;\n\n    float getGrid(float size, float thickness) {\n      vec2 r = localPosition.xz / size;\n      vec2 grid = abs(fract(r - 0.5) - 0.5) / fwidth(r);\n      float line = min(grid.x, grid.y) + 1.0 - thickness;\n      return 1.0 - min(line, 1.0);\n    }\n\n    void main() {\n      float g1 = getGrid(cellSize, cellThickness);\n      float g2 = getGrid(sectionSize, sectionThickness);\n\n      vec3 from = worldCamProjPosition*vec3(fadeFrom);\n      float dist = distance(from, worldPosition.xyz);\n      float d = 1.0 - min(dist / fadeDistance, 1.0);\n      vec3 color = mix(cellColor, sectionColor, min(1.0, sectionThickness * g2));\n\n      gl_FragColor = vec4(color, (g1 + g2) * pow(d, fadeStrength));\n      gl_FragColor.a = mix(0.75 * gl_FragColor.a, gl_FragColor.a, g2);\n      if (gl_FragColor.a <= 0.0) discard;\n\n      #include <tonemapping_fragment>\n      #include <colorspace_fragment>\n    }\n  `,\n)\nextend({ GridMaterial })\n\nconst ref = shallowRef<Mesh>(new Mesh())\nconst plane = new Plane()\nconst upVector = new Vector3(0, 1, 0)\nconst zeroVector = new Vector3(0, 0, 0)\n\nconst { onBeforeRender } = useLoop()\n\nonBeforeRender((state) => {\n  if (!state.camera) { return }\n  plane.setFromNormalAndCoplanarPoint(upVector, zeroVector).applyMatrix4(ref.value.matrixWorld)\n\n  const gridMaterial = ref.value.material as ShaderMaterial\n  const worldCamProjPosition = gridMaterial.uniforms.worldCamProjPosition as Uniform<Vector3>\n  const worldPlanePosition = gridMaterial.uniforms.worldPlanePosition as Uniform<Vector3>\n\n  plane.projectPoint(state.camera.value!.position, worldCamProjPosition.value)\n  worldPlanePosition.value.set(0, 0, 0).applyMatrix4(ref.value.matrixWorld)\n})\n</script>\n\n<template>\n  <TresMesh ref=\"ref\" :frustum-culled=\"false\">\n    <TresGridMaterial\n      :transparent=\"true\"\n      :extensions-derivatives=\"true\"\n      :side=\"props.side\"\n      :cell-size=\"props.cellSize\"\n      :section-size=\"props.sectionSize\"\n      :cell-color=\"props.cellColor\"\n      :section-color=\"props.sectionColor\"\n      :cell-thickness=\"props.cellThickness\"\n      :section-thickness=\"props.sectionThickness\"\n      :fade-distance=\"props.fadeDistance\"\n      :fade-strength=\"props.fadeStrength\"\n      :fade-from=\"props.fadeFrom\"\n      :infinite-grid=\"props.infiniteGrid\"\n      :follow-camera=\"props.followCamera\"\n    />\n    <TresPlaneGeometry :args=\"props.args\" />\n  </TresMesh>\n</template>\n"
  },
  {
    "path": "src/core/staging/Ocean.vue",
    "content": "<script lang=\"ts\" setup>\nimport { useLoop, useTresContext } from '@tresjs/core'\nimport { FrontSide, RepeatWrapping, TextureLoader, Vector3 } from 'three'\nimport { Water } from 'three-stdlib'\nimport { nextTick, onMounted, shallowRef, toRefs } from 'vue'\nimport type { TresColor, TresVector3 } from '@tresjs/core'\nimport type { Sky } from 'three-stdlib'\n\nexport interface OceanProps {\n  /**\n   * The textureWidth of the internal WebGLRenderTarget.\n   *\n   * @default 512\n   * @type {number}\n   * @memberof OceanProps\n   *\n   */\n  textureWidth?: number\n  /**\n   * The textureHeight of the internal WebGLRenderTarget.\n   *\n   * @default 512\n   * @type {number}\n   * @memberof OceanProps\n   *\n   */\n  textureHeight?: number\n  /**\n   * The normal texture of the ocean.\n   * @default 'https://raw.githubusercontent.com/mrdoob/three.js/master/examples/textures/water/Water_1_M_Normal.jpg'\n   * @type {string}\n   * @memberof OceanProps\n   * @see https://threejs.org/docs/#api/en/materials/MeshStandardMaterial\n   */\n  waterNormals?: string\n  /**\n   * The sun direction\n   * @default '[0,0,0]'\n   * @type {TresVector3}\n   * @memberof OceanProps\n   */\n  sunDirection?: TresVector3\n  /**\n   * The sun color.\n   *\n   * @default '#fff'\n   * @type {TresColor}\n   * @memberof OceanProps\n   *\n   */\n  sunColor?: TresColor\n  /**\n   * The water color.\n   *\n   * @default '#001e0f'\n   * @type {TresColor}\n   * @memberof OceanProps\n   *\n   */\n  waterColor?: TresColor\n  /**\n   * The distortion scale of the reflections.\n   * @default 3.7\n   * @type {number}\n   * @memberof OceanProps\n   *\n   */\n  distortionScale?: number\n  /**\n   * The size of the normal texture.\n   *\n   * @default 1\n   * @type {number}\n   * @memberof OceanProps\n   *\n   */\n  size?: number\n  /**\n   * The ClipBias.\n   *\n   * @default 0.0\n   * @type {number}\n   * @memberof OceanProps\n   *\n   */\n  clipBias?: number\n  /**\n   * The alpha factor.\n   *\n   * @default 1.0\n   * @type {number}\n   * @memberof OceanProps\n   *\n   */\n  alpha?: number\n  /**\n   * ThreeJs side material property.\n   *\n   * @default FrontSide\n   * @type {TresVector3}\n   * @memberof OceanProps\n   *\n   */\n  side?: TresVector3\n}\n\nconst props = withDefaults(defineProps<OceanProps>(), {\n  textureWidth: 512,\n  textureHeight: 512,\n  waterNormals: 'https://raw.githubusercontent.com/Tresjs/assets/main/textures/water-normals/Water_1_M_Normal.jpg',\n  sunDirection: () => new Vector3(),\n  sunColor: 0xFFFFFF,\n  waterColor: 0x001E0F,\n  distortionScale: 3.7,\n  size: 1,\n  clipBias: 0.0,\n  alpha: 1.0,\n  side: FrontSide,\n})\n\nconst { textureWidth, textureHeight, waterNormals, sunDirection, sunColor, waterColor, distortionScale, size, clipBias, alpha, side } = toRefs(props)\n\nconst { extend, scene } = useTresContext()\n\nextend({ Water })\n\nconst waterRef = shallowRef()\nconst sunRef = shallowRef()\nconst _fog = scene.value.fog !== undefined\n\ndefineExpose({\n  instance: waterRef,\n})\n\nscene.value.traverse((child) => {\n  if (Object.prototype.hasOwnProperty.call(child, 'isSky')) {\n    sunRef.value = child as Sky\n  }\n})\n\nonMounted(async () => {\n  await nextTick()\n  if (sunRef.value) {\n    const sunPosition = sunRef.value.material.uniforms.sunPosition.value\n    waterRef.value.material.uniforms.sunDirection.value.copy(sunPosition)\n  }\n})\n\nconst normalMap = new TextureLoader().load(waterNormals.value)\n\nnormalMap.wrapS = normalMap.wrapT = RepeatWrapping\n\nconst { onBeforeRender } = useLoop()\n\nonBeforeRender(({ delta /* invalidate */ }) => {\n  if (waterRef.value) {\n    waterRef.value.material.uniforms.time.value += delta\n    // TODO: comment this until invalidate is back in the loop callback on v5\n    // invalidate()\n  }\n})\n</script>\n\n<template>\n  <TresWater\n    ref=\"waterRef\"\n    :rotation-x=\"-Math.PI / 2\"\n    :args=\"[undefined, {\n      textureWidth,\n      textureHeight,\n      waterNormals: normalMap,\n      sunDirection,\n      sunColor,\n      waterColor,\n      distortionScale,\n      fog: _fog,\n      size,\n      clipBias,\n      alpha,\n      side,\n    }]\"\n  >\n    <slot>\n      <TresPlaneGeometry :args=\"[10000, 10000]\" />\n    </slot>\n  </TresWater>\n</template>\n"
  },
  {
    "path": "src/core/staging/Precipitation.vue",
    "content": "<script setup lang=\"ts\">\nimport { useLoop } from '@tresjs/core'\nimport { useTexture } from '../loaders/useTexture'\nimport { shallowRef, toRefs, watch, watchEffect } from 'vue'\nimport type { TresColor } from '@tresjs/core'\nimport type { Texture } from 'three'\n\nexport interface PrecipitationProps {\n  /**\n   * The size of the drops.\n   *\n   * @type {number}\n   * @memberof PrecipitationProps\n   * @default 0.1\n   */\n  size?: number\n  /**\n   * The size of the precipitation area.\n   *\n   * @type {[number, number, number]}\n   * @memberof PrecipitationProps\n   * @default \"[10, 10, 20]\"\n   */\n  area?: [number, number, number]\n  /**\n   * The color of the shadows.\n   *\n   * @default '0xffffff'\n   * @type {TresColor}\n   * @memberof PrecipitationProps\n   *\n   */\n  color?: TresColor\n  /**\n   * Color texture of the drops.\n   *\n   * @type {Texture}\n   * @memberof PrecipitationProps\n   * @default null\n   */\n  map?: string | Texture | null\n  /**\n   * texture of the alphaMap Drops.\n   *\n   * @type {Texture}\n   * @memberof PrecipitationProps\n   * @default null\n   */\n  alphaMap?: string | Texture | null\n  /**\n   * enables the WebGL to know when not to render the pixel.\n   *\n   * @type {number}\n   * @memberof PrecipitationProps\n   * @default 0.01\n   */\n  alphaTest?: number\n  /**\n   * Set the opacity of the drops.\n   *\n   * @type {number}\n   * @memberof PrecipitationProps\n   * @default 0.8\n   */\n  opacity?: number\n  /**\n   * number of drops.\n   *\n   * @type {number}\n   * @memberof PrecipitationProps\n   * @default 5000\n   */\n  count?: number\n  /**\n   * Speed of drops.\n   *\n   * @type {number}\n   * @memberof PrecipitationProps\n   * @default 5000\n   */\n  speed?: number\n  /**\n   * Add randomness to the drops.\n   *\n   * @default 0.5\n   * @type {number}\n   * @memberof PrecipitationProps\n   *\n   */\n  randomness?: number\n  /**\n   * Whether the shadows should write to the depth buffer or not.\n   *\n   * @default false\n   * @type {boolean}\n   * @memberof PrecipitationProps\n   *\n   */\n  depthWrite?: boolean\n  /**\n   * show transparency on the drops texture.\n   *\n   * @type {boolean}\n   * @memberof PrecipitationProps\n   * @default true\n   */\n  transparent?: boolean\n  /**\n   * keep the same size regardless distance.\n   *\n   * @type {boolean}\n   * @memberof PrecipitationProps\n   * @default true\n   */\n  sizeAttenuation?: boolean\n}\n\nconst props = withDefaults(defineProps<PrecipitationProps>(), {\n  size: 0.1,\n  area: () => [10, 10, 20],\n  color: 0xFFFFFF,\n  alphaTest: 0.01,\n  opacity: 0.8,\n  count: 5000,\n  speed: 0.1,\n  randomness: 0.5,\n  depthWrite: false,\n  transparent: true,\n  sizeAttenuation: true,\n})\n\nconst {\n  size,\n  area,\n  color,\n  alphaMap: alphaMapUrl,\n  map: mapUrl,\n  opacity,\n  alphaTest,\n  depthWrite,\n  transparent,\n  sizeAttenuation,\n  count,\n  speed,\n  randomness,\n} = toRefs(props)\n\nconst geometryRef = shallowRef()\nlet positionArray: [] | Float32Array = []\nlet velocityArray: [] | Float32Array = []\n\nconst setPosition = () => {\n  positionArray = new Float32Array(count.value * 3)\n  for (let i = 0; i < count.value; i++) {\n    const i3 = i * 3\n    positionArray[i3] = (Math.random() - 0.5) * area.value[0]\n    positionArray[i3 + 1] = (Math.random() - 0.5) * area.value[1]\n    positionArray[i3 + 2] = (Math.random() - 0.5) * area.value[2]\n  }\n}\nconst setSpeed = () => {\n  velocityArray = new Float32Array(count.value * 2)\n  for (let i = 0; i < count.value * 2; i += 2) {\n    velocityArray[i] = ((Math.random() - 0.5) / 5) * speed.value * randomness.value\n    velocityArray[i + 1] = (Math.random() / 5) * speed.value\n  }\n}\nsetSpeed()\nsetPosition()\n\nwatch((speed), () => {\n  setSpeed()\n})\n\nwatchEffect(() => {\n  if (speed.value) { return }\n  setPosition()\n})\n\n// Load textures if URLs are provided\nconst alphaMapTexture = shallowRef<Texture | null>(null)\nconst mapTexture = shallowRef<Texture | null>(null)\n\nwatchEffect(async () => {\n  if (typeof alphaMapUrl.value === 'string') {\n    const { state: alphaMap } = useTexture(alphaMapUrl.value)\n    alphaMapTexture.value = alphaMap.value\n  }\n  else {\n    alphaMapTexture.value = alphaMapUrl.value ?? null\n  }\n\n  if (typeof mapUrl.value === 'string') {\n    const { state: map } = useTexture(mapUrl.value)\n    mapTexture.value = map.value\n  }\n  else {\n    mapTexture.value = mapUrl.value ?? null\n  }\n})\n\nconst { onBeforeRender } = useLoop()\n\nonBeforeRender(() => {\n  if (geometryRef.value?.attributes.position.array && geometryRef.value?.attributes.position.count) {\n    const positionArray = geometryRef.value.attributes.position.array\n    for (let i = 0; i < geometryRef.value.attributes.position.count; i++) {\n      const velocityX = velocityArray[i * 2]\n      const velocityY = velocityArray[i * 2 + 1]\n\n      positionArray[i * 3] += velocityX\n      positionArray[i * 3 + 1] -= velocityY\n\n      if (positionArray[i * 3] <= -area.value[0] / 2 || positionArray[i * 3] >= area.value[0] / 2) { positionArray[i * 3] = positionArray[i * 3] * -1 }\n      if (positionArray[i * 3 + 1] <= -area.value[1] / 2 || positionArray[i * 3 + 1] >= area.value[1] / 2) { positionArray[i * 3 + 1] = positionArray[i * 3 + 1] * -1 }\n    }\n    geometryRef.value.attributes.position.needsUpdate = true\n\n    // TODO: comment this until invalidate is back in the loop callback on v5\n    // invalidate()\n  }\n})\n\nconst pointsRef = shallowRef()\ndefineExpose({ instance: pointsRef })\n</script>\n\n<template>\n  <TresPoints ref=\"pointsRef\">\n    <TresPointsMaterial\n      :size=\"size\"\n      :color=\"color\"\n      :alpha-map=\"alphaMapTexture\"\n      :map=\"mapTexture\"\n      :opacity=\"opacity\"\n      :alpha-test=\"alphaTest\"\n      :depth-write=\"depthWrite\"\n      :transparent=\"transparent\"\n      :size-attenuation=\"sizeAttenuation\"\n    />\n    <TresBufferGeometry\n      ref=\"geometryRef\"\n      :position=\"[positionArray, 3]\"\n      :velocity=\"[velocityArray]\"\n    />\n  </TresPoints>\n</template>\n"
  },
  {
    "path": "src/core/staging/RandomizedLights/RandomizedLights.ts",
    "content": "import { DirectionalLight, Group, MathUtils, Vector3 } from 'three'\n\nexport default class RandomizedLights extends Group {\n  /** Light position */\n  position: Vector3 = new Vector3(0, 0, 0)\n  /** Radius of the jiggle, higher values make softer light */\n  radius = 1\n  /** Light intensity */\n  intensity = Math.PI\n  /** Ambient occlusion, lower values mean less AO, hight more, you can mix AO and directional light */\n  ambient = 0.5\n  /** If the lights cast shadows */\n  castShadow = true\n  /** Default shadow bias */\n  bias = 0\n\n  constructor(config: Partial<RandomizedLights> = {}) {\n    super()\n    Object.assign(this, config)\n    if (this.count === 0) { this.count = 8 }\n    if (!config.mapSize) {\n      this.mapSize = 512\n    }\n    if (!config.size) {\n      this.size = 10\n    }\n    if (!config.near) {\n      this.near = 0.5\n    }\n    if (!config.far) {\n      this.far = 500\n    }\n  }\n\n  get length() {\n    return this.position.length()\n  }\n\n  set count(n: number) {\n    this.clear()\n    for (let i = 0; i < n; i++) {\n      this.add(new DirectionalLight('white', this.intensity))\n    }\n  }\n\n  get count() {\n    return this.children.filter(c => 'isDirectionalLight' in c).length\n  }\n\n  get mapSize() {\n    return this.lights[0].shadow.mapSize.width\n  }\n\n  set mapSize(n: number) {\n    for (const light of this.lights) {\n      // NOTE: Changing the map size requires 2 modifications.\n      // https://discourse.threejs.org/t/change-resolution-of-shadows-dinamically/50744/6\n      light.shadow.mapSize.set(n, n)\n      light.shadow.map?.setSize(n, n)\n    }\n  }\n\n  get size() {\n    return this.lights[0].shadow.camera.right\n  }\n\n  set size(n: number) {\n    for (const light of this.lights) {\n      light.shadow.camera.left = -n\n      light.shadow.camera.right = n\n      light.shadow.camera.top = n\n      light.shadow.camera.bottom = -n\n    }\n  }\n\n  get near() {\n    return this.lights[0].shadow.camera.near\n  }\n\n  set near(n: number) {\n    for (const light of this.lights) {\n      light.shadow.camera.near = n\n    }\n  }\n\n  get far() {\n    return this.lights[0].shadow.camera.far\n  }\n\n  set far(n: number) {\n    for (const light of this.lights) {\n      light.shadow.camera.far = n\n    }\n  }\n\n  get lights(): DirectionalLight[] {\n    return this.children.filter(c => 'isDirectionalLight' in c) as DirectionalLight[]\n  }\n\n  update() {\n    const lights = this.lights\n    const lightIntensity = this.intensity / lights.length\n    let ambientCount = Math.floor(this.ambient * lights.length)\n\n    for (const light of lights) {\n      light.castShadow = this.castShadow\n      light.shadow.bias = this.bias\n\n      light.intensity = lightIntensity\n\n      if (ambientCount-- > 0) {\n        const lambda = Math.acos(2 * Math.random() - 1) - Math.PI / 2.0\n        const phi = 2 * Math.PI * Math.random()\n        light.position.set(\n          Math.cos(lambda) * Math.cos(phi) * this.length,\n          Math.abs(Math.cos(lambda) * Math.sin(phi) * this.length),\n          Math.sin(lambda) * this.length,\n        )\n      }\n      else {\n        if (Math.random() > this.ambient) {\n          light.position.set(\n            this.position.x + MathUtils.randFloatSpread(this.radius),\n            this.position.y + MathUtils.randFloatSpread(this.radius),\n            this.position.z + MathUtils.randFloatSpread(this.radius),\n          )\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "src/core/staging/RandomizedLights/component.vue",
    "content": "<script setup lang=\"ts\">\nimport { computed, shallowRef } from 'vue'\nimport type { VectorFlexibleParams } from '@tresjs/core'\nimport { extend, normalizeVectorFlexibleParam } from '@tresjs/core'\nimport RandomizedLights from './RandomizedLights'\n\nexport interface RandomizedLightsProps {\n  /** Number of lights, 8 */\n  count?: number\n  /** Radius of the jiggle, higher values make softer light, 1 */\n  radius?: number\n  /** Light intensity, Math.PI */\n  intensity?: number\n  /** \"Ambient occlusion\" to directional light ratio, lower values mean less AO, 0.5 */\n  ambient?: number\n  /** If the lights cast shadows, true */\n  castShadow?: boolean\n  /** Default shadow bias, 0 */\n  bias?: number\n  /** Size of the lights' shadow map, 512 */\n  mapSize?: number\n  /** Size of the lights' shadow camera frustum, 10 */\n  size?: number\n  /** Lights' shadow camera near value, 0.5 */\n  near?: number\n  /** Lights' shadow camera far value, 500 */\n  far?: number\n  /** Position, [5, 5, -10] */\n  position?: VectorFlexibleParams\n}\n\nconst props = withDefaults(defineProps<RandomizedLightsProps>(), {\n  count: 8,\n  radius: 1,\n  intensity: Math.PI,\n  ambient: 0.5,\n  castShadow: true,\n  bias: 0,\n  mapSize: 512,\n  size: 10,\n  near: 0.5,\n  far: 500,\n  position: () => [5, 5, -10],\n})\n\nextend({ RandomizedLights })\n\nconst lightsRef = shallowRef()\n\nconst pos = computed(() => normalizeVectorFlexibleParam(props.position))\n\ndefineExpose({ instance: lightsRef })\n</script>\n\n<template>\n  <TresRandomizedLights\n    ref=\"lightsRef\"\n    :count=\"count\"\n    :radius=\"radius\"\n    :intensity=\"intensity\"\n    :ambient=\"ambient\"\n    :cast-shadow=\"castShadow\"\n    :bias=\"bias\"\n    :map-size=\"mapSize\"\n    :size=\"size\"\n    :near=\"near\"\n    :far=\"far\"\n    :position=\"pos\"\n  />\n</template>\n"
  },
  {
    "path": "src/core/staging/Sky.vue",
    "content": "<script setup lang=\"ts\">\nimport { useTres } from '@tresjs/core'\n// eslint-disable-file vue/attribute-hyphenation\nimport { MathUtils, Vector3 } from 'three'\nimport { Sky as SkyImpl } from 'three-stdlib'\nimport { computed, watch } from 'vue'\n\nexport interface SkyProps {\n  /**\n   * Haziness\n   * @param {number} turbidity\n   */\n  turbidity?: number\n  /**\n   * [Rayleigh scattering](https://en.wikipedia.org/wiki/Rayleigh_scattering)\n   */\n  rayleigh?: number\n  /**\n   * [Mie scattering](https://en.wikipedia.org/wiki/Mie_scattering) amount\n   */\n  mieCoefficient?: number\n  /**\n   * [Mie scattering](https://en.wikipedia.org/wiki/Mie_scattering) direction\n   */\n  mieDirectionalG?: number\n  /**\n   * Sun's elevation from the horizon, in degrees\n   */\n  elevation?: number\n  /**\n   * Sun's [azimuth angle](https://en.wikipedia.org/wiki/Solar_azimuth_angle), in degrees – its horizontal coordinate on the horizon\n   */\n  azimuth?: number\n  /**\n   * Sky box scale\n   */\n  distance?: number\n}\n\nconst props = withDefaults(defineProps<SkyProps>(), {\n  turbidity: 3.4,\n  rayleigh: 3,\n  mieCoefficient: 0.005,\n  mieDirectionalG: 0.7,\n  elevation: 0.6,\n  azimuth: 180,\n  distance: 450000,\n})\n\nconst { invalidate } = useTres()\n\nwatch(props, () => {\n  invalidate()\n})\n\nconst skyImpl = new SkyImpl()\nconst sunPosition = computed(() =>\n  getSunPosition(props.azimuth, props.elevation),\n)\n\nfunction getSunPosition(azimuth: number, elevation: number) {\n  const phi = MathUtils.degToRad(90 - elevation)\n  const theta = MathUtils.degToRad(azimuth)\n  return new Vector3().setFromSphericalCoords(1, phi, theta)\n}\n\ndefineExpose({\n  instance: skyImpl,\n  sunPosition: sunPosition.value,\n})\n</script>\n\n<template>\n  <primitive\n    :object=\"skyImpl\"\n    :material-uniforms-turbidity-value=\"props.turbidity\"\n    :material-uniforms-rayleigh-value=\"props.rayleigh\"\n    :material-uniforms-mieCoefficient-value=\"props.mieCoefficient\"\n    :material-uniforms-mieDirectionalG-value=\"props.mieDirectionalG\"\n    :material-uniforms-sunPosition-value=\"sunPosition\"\n    :scale=\"props.distance\"\n  />\n</template>\n"
  },
  {
    "path": "src/core/staging/Smoke.vue",
    "content": "<script setup lang=\"ts\">\nimport { useLoop, useTresContext } from '@tresjs/core'\nimport { computed, shallowRef, toRefs } from 'vue'\nimport type { TresColor } from '@tresjs/core'\nimport type { Object3D } from 'three'\nimport { useTexture } from '../loaders/useTexture'\n\nexport interface SmokeProps {\n  /**\n   * The color of the smoke.\n   * @default 0xffffff\n   * @type {TresColor}\n   * @memberof SmokeProps\n   * @see https://threejs.org/docs/#api/en/materials/MeshStandardMaterial\n   */\n  color?: TresColor\n  /**\n   * The strength of the opacity.\n   * @default 0.5\n   * @type {number}\n   * @memberof SmokeProps\n   * @see https://threejs.org/docs/#api/en/materials/MeshStandardMaterial\n   */\n  opacity?: number\n  /**\n   * The rotation speed of the smoke.\n   * @default 0.4\n   * @type {number}\n   * @memberof SmokeProps\n   * @see https://threejs.org/docs/#api/en/materials/MeshStandardMaterial\n   */\n  speed?: number\n  /**\n   * The base width.\n   * @default 4\n   * @type {number}\n   * @memberof SmokeProps\n   * @see https://threejs.org/docs/#api/en/materials/MeshBasicMaterial\n   */\n  width?: number\n  /**\n   * The base depth.\n   * @default 10\n   * @type {number}\n   * @memberof SmokeProps\n   * @see https://threejs.org/docs/#api/en/geometries/PlaneGeometry\n   */\n  depth?: number\n  /**\n   * The number of smoke to render.\n   * @default 10\n   * @type {number}\n   * @memberof SmokeProps\n   * @see https://threejs.org/docs/#api/en/materials/MeshStandardMaterial\n   */\n  segments?: number\n  /**\n   * The texture of the smoke.\n   * @default 'https://raw.githubusercontent.com/Tresjs/assets/main/textures/clouds/defaultCloud.png'\n   * @type {string}\n   * @memberof SmokeProps\n   * @see https://threejs.org/docs/#api/en/materials/MeshStandardMaterial\n   */\n  texture?: string\n  /**\n   * The depthTest.\n   * @default true\n   * @type {boolean}\n   * @memberof SmokeProps\n   * @see https://threejs.org/docs/#api/en/materials/MeshStandardMaterial\n   */\n  depthTest?: boolean\n}\n\nconst props = withDefaults(defineProps<SmokeProps>(), {\n  opacity: 0.5,\n  speed: 0.4,\n  width: 10,\n  depth: 1.5,\n  segments: 20,\n  texture: 'https://raw.githubusercontent.com/Tresjs/assets/main/textures/clouds/defaultCloud.png',\n  color: '#ffffff',\n  depthTest: true,\n})\n\nconst { width, depth, segments, texture, color, depthTest, opacity, speed } = toRefs(props)\n\nconst smokeRef = shallowRef()\nconst groupRef = shallowRef()\n\ndefineExpose({\n  instance: smokeRef,\n})\n\nconst smoke = [...[segments]].map((_, index) => ({\n  x: width.value / 2 - Math.random() * width.value,\n  y: width.value / 2 - Math.random() * width.value,\n  scale: 0.4 + Math.sin(((index + 1) / segments.value) * Math.PI) * ((0.2 + Math.random()) * 10),\n  density: Math.max(0.2, Math.random()),\n  rotation: Math.max(0.002, 0.005 * Math.random()) * speed.value,\n}))\n\nconst calculateOpacity = (scale: number, density: number): number => (scale / 6) * density * opacity.value\n\nconst { state: map } = useTexture(texture.value)\n\nconst { renderer, camera } = useTresContext()\nconst colorSpace = computed(() => renderer.instance?.outputColorSpace)\n\nconst { onBeforeRender } = useLoop()\n\nonBeforeRender(() => {\n  if (smokeRef.value && camera.activeCamera.value && groupRef.value) {\n    groupRef.value?.children.forEach((child: Object3D, index: number) => {\n      child.rotation.z += smoke[index].rotation\n    })\n    smokeRef.value.lookAt(camera.activeCamera.value?.position)\n    // TODO: comment this until invalidate is back in the loop callback on v5\n    // invalidate()\n  }\n})\n</script>\n\n<template>\n  <TresGroup\n    ref=\"smokeRef\"\n    v-bind=\"$attrs\"\n  >\n    <TresGroup\n      ref=\"groupRef\"\n      :position=\"[0, 0, (segments / 2) * depth]\"\n    >\n      <TresMesh\n        v-for=\"({ scale, x, y, density }, index) in smoke\"\n        :key=\"`${index}`\"\n        :position=\"[x, y, -index * depth]\"\n      >\n        <TresPlaneGeometry\n          :scale=\"[scale, scale, scale]\"\n          :rotation=\"[0, 0, 0]\"\n        />\n        <TresMeshStandardMaterial\n          :map=\"map\"\n          :depth-test=\"depthTest\"\n          :color-space=\"colorSpace\"\n          :color=\"color\"\n          :depth-write=\"false\"\n          transparent\n          :opacity=\"calculateOpacity(scale, density)\"\n        />\n      </TresMesh>\n    </TresGroup>\n  </TresGroup>\n</template>\n"
  },
  {
    "path": "src/core/staging/SoftShadows.vue",
    "content": "<script setup lang=\"ts\">\nimport { useTres } from '@tresjs/core'\nimport type { TresRenderer } from '@tresjs/core'\nimport type { Camera, Scene } from 'three'\nimport { ShaderChunk, WebGLRenderer } from 'three'\nimport { onUnmounted, watch } from 'vue'\n\n// NOTE: Sources\n// https://github.com/mrdoob/three.js/blob/master/examples/webgl_shadowmap_pcss.html\n// https://github.com/pmndrs/drei/blob/master/src/core/softShadows.tsx\n\ninterface SoftShadowsProps {\n  /** Size of the light source (the larger the softer the light), default: 25 */\n  size?: number\n  /** Number of samples (more samples less noise but more expensive), default: 10 */\n  samples?: number\n  /** Depth focus, use it to shift the focal point (where the shadow is the sharpest), default: 0 (the beginning) */\n  focus?: number\n}\n\nconst props = withDefaults(defineProps<SoftShadowsProps>(), {\n  size: 25,\n  samples: 10,\n  focus: 0,\n})\n\nconst PCSSGetShadow = `\nreturn PCSS( shadowMap, shadowCoord );\n`\nconst getPcss = ({ focus = 0, size = 25, samples = 10 }: SoftShadowsProps = {}) => `\n#define PENUMBRA_FILTER_SIZE float(${size})\n#define RGB_NOISE_FUNCTION(uv) (randRGB(uv))\nvec3 randRGB(vec2 uv) {\n  return vec3(\n    fract(sin(dot(uv, vec2(12.75613, 38.12123))) * 13234.76575),\n    fract(sin(dot(uv, vec2(19.45531, 58.46547))) * 43678.23431),\n    fract(sin(dot(uv, vec2(23.67817, 78.23121))) * 93567.23423)\n  );\n}\n\nvec3 lowPassRandRGB(vec2 uv) {\n  // 3x3 convolution (average)\n  // can be implemented as separable with an extra buffer for a total of 6 samples instead of 9\n  vec3 result = vec3(0);\n  result += RGB_NOISE_FUNCTION(uv + vec2(-1.0, -1.0));\n  result += RGB_NOISE_FUNCTION(uv + vec2(-1.0,  0.0));\n  result += RGB_NOISE_FUNCTION(uv + vec2(-1.0, +1.0));\n  result += RGB_NOISE_FUNCTION(uv + vec2( 0.0, -1.0));\n  result += RGB_NOISE_FUNCTION(uv + vec2( 0.0,  0.0));\n  result += RGB_NOISE_FUNCTION(uv + vec2( 0.0, +1.0));\n  result += RGB_NOISE_FUNCTION(uv + vec2(+1.0, -1.0));\n  result += RGB_NOISE_FUNCTION(uv + vec2(+1.0,  0.0));\n  result += RGB_NOISE_FUNCTION(uv + vec2(+1.0, +1.0));\n  result *= 0.111111111; // 1.0 / 9.0\n  return result;\n}\nvec3 highPassRandRGB(vec2 uv) {\n  // by subtracting the low-pass signal from the original signal, we're being left with the high-pass signal\n  // hp(x) = x - lp(x)\n  return RGB_NOISE_FUNCTION(uv) - lowPassRandRGB(uv) + 0.5;\n}\n\n\nvec2 vogelDiskSample(int sampleIndex, int sampleCount, float angle) {\n  const float goldenAngle = 2.399963f; // radians\n  float r = sqrt(float(sampleIndex) + 0.5f) / sqrt(float(sampleCount));\n  float theta = float(sampleIndex) * goldenAngle + angle;\n  float sine = sin(theta);\n  float cosine = cos(theta);\n  return vec2(cosine, sine) * r;\n}\nfloat penumbraSize( const in float zReceiver, const in float zBlocker ) { // Parallel plane estimation\n  return (zReceiver - zBlocker) / zBlocker;\n}\nfloat findBlocker(sampler2D shadowMap, vec2 uv, float compare, float angle) {\n  float texelSize = 1.0 / float(textureSize(shadowMap, 0).x);\n  float blockerDepthSum = float(${focus});\n  float blockers = 0.0;\n\n  int j = 0;\n  vec2 offset = vec2(0.);\n  float depth = 0.;\n\n  #pragma unroll_loop_start\n  for(int i = 0; i < ${samples}; i ++) {\n    offset = (vogelDiskSample(j, ${samples}, angle) * texelSize) * 2.0 * PENUMBRA_FILTER_SIZE;\n    depth = unpackRGBAToDepth( texture2D( shadowMap, uv + offset));\n    if (depth < compare) {\n      blockerDepthSum += depth;\n      blockers++;\n    }\n    j++;\n  }\n  #pragma unroll_loop_end\n\n  if (blockers > 0.0) {\n    return blockerDepthSum / blockers;\n  }\n  return -1.0;\n}\n\n        \nfloat vogelFilter(sampler2D shadowMap, vec2 uv, float zReceiver, float filterRadius, float angle) {\n  float texelSize = 1.0 / float(textureSize(shadowMap, 0).x);\n  float shadow = 0.0f;\n  int j = 0;\n  vec2 vogelSample = vec2(0.0);\n  vec2 offset = vec2(0.0);\n  #pragma unroll_loop_start\n  for (int i = 0; i < ${samples}; i++) {\n    vogelSample = vogelDiskSample(j, ${samples}, angle) * texelSize;\n    offset = vogelSample * (1.0 + filterRadius * float(${size}));\n    shadow += step( zReceiver, unpackRGBAToDepth( texture2D( shadowMap, uv + offset ) ) );\n    j++;\n  }\n  #pragma unroll_loop_end\n  return shadow * 1.0 / ${samples}.0;\n}\n\nfloat PCSS (sampler2D shadowMap, vec4 coords) {\n  vec2 uv = coords.xy;\n  float zReceiver = coords.z; // Assumed to be eye-space z in this code\n  float angle = highPassRandRGB(gl_FragCoord.xy).r * PI2;\n  float avgBlockerDepth = findBlocker(shadowMap, uv, zReceiver, angle);\n  if (avgBlockerDepth == -1.0) {\n    return 1.0;\n  }\n  float penumbraRatio = penumbraSize(zReceiver, avgBlockerDepth);\n  return vogelFilter(shadowMap, uv, zReceiver, 1.25 * penumbraRatio, angle);\n}`\n\nconst originalShadowsFragment = ShaderChunk.shadowmap_pars_fragment\nconst { renderer, scene, camera } = useTres()\n\nfunction injectSoftShadowsFragment(renderer: TresRenderer, props: SoftShadowsProps) {\n  // overwrite shadowmap code\n\n  let shader = originalShadowsFragment\n\n  shader = shader.replace(\n    '#ifdef USE_SHADOWMAP',\n    `#ifdef USE_SHADOWMAP\n    ${getPcss(props)}`,\n  )\n\n  shader = shader.replace(\n    '#if defined( SHADOWMAP_TYPE_PCF )',\n    `${PCSSGetShadow} \n    #if defined( SHADOWMAP_TYPE_PCF )`,\n  )\n\n  ShaderChunk.shadowmap_pars_fragment = shader\n\n  // renderer\n  renderer.shadowMap.enabled = true\n}\n\nfunction reset(renderer: TresRenderer, scene: Scene, camera: Camera) {\n  if (renderer instanceof WebGLRenderer) {\n    scene.traverse((object) => {\n      if ('material' in object && object.material) {\n        renderer.properties.remove(object.material)\n        if (typeof object.material === 'object' && 'dispose' in object.material && typeof object.material.dispose === 'function') { object.material.dispose?.() }\n      }\n    })\n    if (renderer.info.programs) {\n      renderer.info.programs.length = 0\n    }\n  }\n  renderer.compile(scene, camera)\n}\n\nonUnmounted(() => {\n  if (camera.value) {\n    ShaderChunk.shadowmap_pars_fragment = originalShadowsFragment\n    reset(renderer, scene.value, camera.value)\n  }\n})\n\nwatch(props, () => {\n  if (camera.value) {\n    injectSoftShadowsFragment(renderer, props)\n    reset(renderer, scene.value, camera.value)\n  }\n}, { immediate: true })\n</script>\n\n<template>\n  <TresGroup />\n</template>\n"
  },
  {
    "path": "src/core/staging/Sparkles/ShaderData.ts",
    "content": "import { watchThrottled } from '@vueuse/core'\nimport {\n  ClampToEdgeWrapping,\n  DataTexture,\n  MathUtils,\n  RGBAFormat,\n  UnsignedByteType,\n  UVMapping,\n} from 'three'\nimport { isRef, shallowRef, triggerRef, watch } from 'vue'\nimport type { MaybeRef, Ref } from 'vue'\nimport {\n  normalizeColorGradient,\n  normalizeFlexibleVector3Gradient,\n  normalizeScalarGradient,\n} from './../../../utils/Gradient'\nimport type {\n  GradientScalar,\n  GradientTresColor,\n  GradientVectorFlexibleParams,\n} from './../../../utils/Gradient'\n\nexport type CanvasGradientRenderer<T> = (\n  g: CanvasGradient,\n  entry: ShaderDataEntry<T>\n) => void\n\nexport class ShaderData {\n  private entries: ShaderDataEntry<any>[]\n  private resolution: number\n\n  constructor(entries: ShaderDataEntry<any>[], resolution: number) {\n    this.entries = entries\n    this.resolution = resolution\n  }\n\n  useTexture() {\n    return new ShaderDataTexture(this.entries, this.resolution).use()\n  }\n}\n\nexport class ShaderDataEntry<T> {\n  data: T\n  ref: Ref<T> | null\n  name: string\n  valueMin: number\n  valueMax: number\n  suffix: string\n  renderToCanvasGradient: CanvasGradientRenderer<T>\n\n  constructor(\n    data: MaybeRef<T>,\n    name: string,\n    valueMin: number,\n    valueMax: number,\n    suffix: string,\n    renderToCanvasGradient: (\n      gradient: CanvasGradient,\n      data: ShaderDataEntry<T>\n    ) => void,\n  ) {\n    this.data = isRef(data) ? data.value : data\n    this.ref = isRef(data) ? data : null\n    this.name = name\n    this.valueMin = valueMin\n    this.valueMax = valueMax\n    this.suffix = suffix\n    this.renderToCanvasGradient = renderToCanvasGradient\n  }\n}\n\nexport class ShaderDataEntryTresColorGradient extends ShaderDataEntry<GradientTresColor> {\n  constructor(\n    data: MaybeRef<GradientTresColor>,\n    name = 'color',\n    valueMin = 0,\n    valueMax = 1,\n    suffix = 'rgba',\n    renderToCanvasGradient = GradientTresColorRenderToCanvasGradient,\n  ) {\n    super(data, name, valueMin, valueMax, suffix, renderToCanvasGradient)\n  }\n}\n\nexport class ShaderDataEntryScalarGradient extends ShaderDataEntry<GradientScalar> {\n  constructor(\n    data: MaybeRef<GradientScalar>,\n    name = 'scalar',\n    valueMin = 0,\n    valueMax = 1,\n    suffix = 'x',\n    renderToCanvasGradient = GradientScalarRenderToCanvasGradient,\n  ) {\n    super(data, name, valueMin, valueMax, suffix, renderToCanvasGradient)\n  }\n}\n\nexport class ShaderDataEntryXyzGradient extends ShaderDataEntry<GradientVectorFlexibleParams> {\n  constructor(\n    data: MaybeRef<GradientVectorFlexibleParams>,\n    name = 'scalar3',\n    valueMin = 0,\n    valueMax = 1,\n    suffix = 'xyz',\n    renderToCanvasGradient = GradientXyzRenderToCanvasGradient,\n  ) {\n    super(data, name, valueMin, valueMax, suffix, renderToCanvasGradient)\n  }\n}\n\nclass ShaderDataTexture {\n  private entries: ShaderDataEntry<any>[]\n  private size: number\n  private dirty = shallowRef(0)\n  private context: CanvasRenderingContext2D\n\n  constructor(entries: ShaderDataEntry<any>[], resolution: number) {\n    this.entries = entries\n    this.size = Math.max(resolution, entries.length)\n\n    const canvas = document.createElement('canvas')\n    canvas.height = this.size\n    canvas.width = this.size\n    this.context = canvas.getContext('2d') as CanvasRenderingContext2D\n  }\n\n  use() {\n    const texture = this.build()\n    const textureRef = shallowRef(texture)\n\n    for (const entry of this.entries) {\n      if (entry.ref) {\n        watch(entry.ref, () => {\n          entry.data = entry.ref?.value\n          triggerRef(this.dirty)\n        })\n      }\n    }\n\n    watchThrottled(\n      this.dirty,\n      () => {\n        this.build(texture)\n        textureRef.value = texture\n      },\n      { throttle: 1000 / 60 },\n    )\n\n    return {\n      texture: textureRef,\n      dispose: () => texture.dispose(),\n      yFor: this.entries.reduce((obj, entry, i) => {\n        obj[entry.name] = (i + 0.5) / this.size\n        return obj\n      }, {} as Record<string, number>),\n    }\n  }\n\n  private build(recycledTexture?: DataTexture) {\n    this.entries.forEach((entry: ShaderDataEntry<any>, i) => {\n      const gradient = this.context.createLinearGradient(0, i, this.size, i)\n      entry.renderToCanvasGradient(gradient, entry)\n      this.context.fillStyle = gradient\n      this.context.fillRect(0, i, this.size, 1)\n    })\n\n    if (recycledTexture) {\n      recycledTexture.source.data = this.context.getImageData(\n        0,\n        0,\n        this.size,\n        this.size,\n      )\n    }\n\n    const texture\n      = recycledTexture\n        ?? new DataTexture(\n          this.context.getImageData(0, 0, this.size, this.size).data,\n          this.size,\n          this.size,\n          RGBAFormat,\n          UnsignedByteType,\n          UVMapping,\n          ClampToEdgeWrapping,\n          ClampToEdgeWrapping,\n        )\n\n    texture.needsUpdate = true\n\n    return texture\n  }\n}\n\nfunction clampedMapLinear(\n  v: number,\n  minIn: number,\n  maxIn: number,\n  minOut: number,\n  maxOut: number,\n) {\n  return MathUtils.mapLinear(MathUtils.clamp(v, minIn, maxIn), minIn, maxIn, minOut, maxOut)\n}\n\nfunction GradientTresColorRenderToCanvasGradient(\n  g: CanvasGradient,\n  entry: ShaderDataEntryTresColorGradient,\n) {\n  return normalizeColorGradient(entry.data).forEach(([offset, color]) =>\n    g.addColorStop(\n      offset,\n      `rgb(${color.r * 255}, ${color.g * 255}, ${color.b * 255})`,\n    ),\n  )\n}\n\nfunction GradientScalarRenderToCanvasGradient(\n  g: CanvasGradient,\n  entry: ShaderDataEntryScalarGradient,\n) {\n  return normalizeScalarGradient(entry.data).forEach(([offset, scalar]) => {\n    g.addColorStop(\n      offset,\n      `rgb(${clampedMapLinear(\n        scalar,\n        entry.valueMin,\n        entry.valueMax,\n        0,\n        255,\n      )}, 0, 0)`,\n    )\n  })\n}\n\nfunction GradientXyzRenderToCanvasGradient(\n  g: CanvasGradient,\n  entry: ShaderDataEntryXyzGradient,\n) {\n  return normalizeFlexibleVector3Gradient(entry.data).forEach(([offset, xyz]) =>\n    g.addColorStop(\n      offset,\n      `rgb(${xyz.map(v =>\n        clampedMapLinear(v, entry.valueMin, entry.valueMax, 0, 255),\n      )})`,\n    ),\n  )\n}\n"
  },
  {
    "path": "src/core/staging/Sparkles/ShaderDataBuilder.ts",
    "content": "import type { MaybeRef } from 'vue'\nimport {\n  ShaderData,\n  ShaderDataEntryScalarGradient,\n  ShaderDataEntryTresColorGradient,\n  ShaderDataEntryXyzGradient,\n} from './ShaderData'\nimport type {\n  GradientScalar,\n  GradientTresColor,\n  GradientVectorFlexibleParams,\n} from './../../../utils/Gradient'\nimport type {\n  CanvasGradientRenderer,\n  ShaderDataEntry,\n} from './ShaderData'\n\ntype rgbaSuffixes = ['r', 'rg', 'rgb', 'rgba']\ntype xyzwSuffixes = ['x', 'xy', 'xyz', 'xyzw']\ntype ShaderSuffix =\n  | (rgbaSuffixes)[number]\n  | (xyzwSuffixes)[number]\n\nexport default class ShaderDataBuilder {\n  private entries: ShaderDataEntry<any>[]\n  private resolution: number\n\n  constructor(resolution = 256) {\n    this.resolution = resolution\n    this.entries = []\n  }\n\n  withResolution(resolution: number) {\n    this.resolution = resolution\n    return this\n  }\n\n  get add() {\n    return new ShaderDataBuilderAdd((entry: ShaderDataEntry<any>) =>\n      this.onAdd<any>(entry),\n    )\n  }\n\n  build() {\n    return new ShaderData(this.entries, this.resolution)\n  }\n\n  private onAdd<T>(entry: ShaderDataEntry<T>) {\n    this.entries.push(entry)\n    const entryBuilder = new ShaderDataEntryBuilder<T>(entry, this)\n    return entryBuilder\n  }\n}\nclass ShaderDataEntryBuilder<T> {\n  private entry: ShaderDataEntry<T>\n  private parent: ShaderDataBuilder\n\n  constructor(entry: ShaderDataEntry<T>, parent: ShaderDataBuilder) {\n    this.entry = entry\n    this.parent = parent\n  }\n\n  id(s: string) {\n    this.entry.name = s\n    return this\n  }\n\n  range(min: number, max: number) {\n    this.entry.valueMin = min\n    this.entry.valueMax = max\n    return this\n  }\n\n  suffix(s: ShaderSuffix) {\n    this.entry.suffix = s\n    return this\n  }\n\n  canvasGradientRenderer(fn: CanvasGradientRenderer<T>) {\n    this.entry.renderToCanvasGradient = fn\n    return this\n  }\n\n  /**\n   * Add another entry to the ShaderDataBuilder\n   */\n  get add() {\n    return this.parent.add\n  }\n\n  /**\n   * Finalize the ShaderDataBuilder\n   * @returns ShaderData\n   */\n  build() {\n    return this.parent.build()\n  }\n}\n\nclass ShaderDataBuilderAdd {\n  private onAdd: (entry: ShaderDataEntry<any>) => ShaderDataEntryBuilder<any>\n\n  constructor(\n    onAdd: (entry: ShaderDataEntry<any>) => ShaderDataEntryBuilder<any>,\n  ) {\n    this.onAdd = onAdd\n  }\n\n  GradientTresColor(data: MaybeRef<GradientTresColor>) {\n    return this.onAdd(new ShaderDataEntryTresColorGradient(data))\n  }\n\n  Gradient01(data: MaybeRef<GradientScalar>) {\n    return this.onAdd(new ShaderDataEntryScalarGradient(data, 'zeroOne', 0, 1))\n  }\n\n  GradientScalar(data: MaybeRef<GradientScalar>, min: number, max: number) {\n    return this.onAdd(\n      new ShaderDataEntryScalarGradient(data, 'scalar', min, max),\n    )\n  }\n\n  GradientXyz(\n    data: MaybeRef<GradientVectorFlexibleParams>,\n    min: number,\n    max: number,\n  ) {\n    return this.onAdd(\n      new ShaderDataEntryXyzGradient(data, 'position', min, max),\n    )\n  }\n}\n"
  },
  {
    "path": "src/core/staging/Sparkles/component.vue",
    "content": "<script lang=\"ts\" setup>\nimport { useLoop, useTresContext } from '@tresjs/core'\nimport {\n  AdditiveBlending,\n  IcosahedronGeometry,\n  Object3D,\n  Points,\n  Quaternion,\n  REVISION,\n  ShaderMaterial,\n  Uniform,\n  Vector3,\n} from 'three'\nimport { onMounted, onUnmounted, toRefs, watch } from 'vue'\nimport type { TresColor, VectorFlexibleParams } from '@tresjs/core'\nimport type { Blending, BufferGeometry, IUniform, ShaderMaterialParameters, Texture } from 'three'\nimport type { Ref } from 'vue'\nimport ShaderDataBuilder from './ShaderDataBuilder'\nimport useEmptyDataTexture from './useEmptyDataTexture'\nimport { useTexture } from '../../loaders/useTexture'\nimport type { Gradient } from '../../../utils/Gradient'\n\ninterface SparkleProps {\n  /**\n   * Texture or image path for individual sparkles\n   */\n  map?: Texture | string\n  /**\n   * Vertices of the geometry will be used to emit sparkles. Geometry normals are used for sparkles' traveling direction and for responding to the directional light prop.\n   *\n   * - If provided, the component will use the passed geometry.\n   * - If no geometry is provided, the component will try to make a copy of the parent object's geometry.\n   * - If no parent geometry exists, the component will create and use an IcosphereGeometry.\n   */\n  geometry?: Object3D | BufferGeometry\n  /**\n   * Particles \"light up\" when their normal \"faces\" the light. If no `directionalLight` is provided, the default \"up\" vector will be used.\n   */\n  directionalLight?: Object3D\n  /**\n   * Particle lifetime in seconds\n   */\n  lifetimeSec?: number\n  /**\n   * Particle cooldown in seconds – time between lifetime end and respawn\n   */\n  cooldownSec?: number\n  /**\n   * Number from 0-1 indicating how closely the particle needs to be faced towards the light to \"light up\". (Lower == more flexible)\n   */\n  normalThreshold?: number\n  /**\n   * Scale of the noise period (lower == more slowly cycling noise)\n   */\n  noiseScale?: number\n  /**\n   * Noise coefficient applied to particle scale\n   */\n  scaleNoise?: number\n  /**\n   * Noise coefficient applied to particle offset\n   */\n  offsetNoise?: number\n  /**\n   * Noise coefficient applied to particle lifetime\n   */\n  lifetimeNoise?: number\n  /**\n   * Particle scale multiplier\n   */\n  size?: number\n  /**\n   * Opacity multiplier\n   */\n  alpha?: number\n  /**\n   * Offset multiplier\n   */\n  offset?: number\n  /**\n   * Surface distance multiplier\n   */\n  surfaceDistance?: number\n  /**\n   * '*Sequence' props: specify how a particle changes as it \"progresses\". See also \"mix*\" props.\n   *\n   * Color sequence as particles progress\n   */\n  sequenceColor?: Gradient<TresColor>\n  /**\n   * Opacity sequence as particles progress\n   */\n  sequenceAlpha?: Gradient<number>\n  /**\n   * Distance sequence as particles progress\n   */\n  sequenceOffset?: Gradient<VectorFlexibleParams>\n  /**\n   * Noise sequence as particles progress\n   */\n  sequenceNoise?: Gradient<VectorFlexibleParams>\n  /**\n   * Size sequence as particles progress\n   */\n  sequenceSize?: Gradient<number>\n  /**\n   * Distance from surface (along normal) as particles progress\n   */\n  sequenceSurfaceDistance?: Gradient<number>\n  /**\n   * 'mix*' props: A particle \"progresses\" with a mix of two factors:\n   *\n   * its normal \"facing\" the directionalLight\n   * its lifetime\n   *\n   * 'mix*' props specify the relationship between the two factors.\n   *\n   * How is a particle's progress for color calculated? (0: normal, 1: particle lifetime)\n   */\n  mixColor?: number\n  /**\n   * How is a particle's progress for alpha calculated? (0: normal, 1: particle lifetime)\n   */\n  mixAlpha?: number\n  /**\n   * How is a particle's progress for offset calculated? (0: normal, 1: particle lifetime)\n   */\n  mixOffset?: number\n  /**\n   * How is a particle's progress for size calculated? (0: normal, 1: particle lifetime)\n   */\n  mixSize?: number\n  /**\n   * How is a particle's progress for surface distance calculated? (0: normal, 1: particle lifetime)\n   */\n  mixSurfaceDistance?: number\n  /**\n   * How is a particle's progress for lifetime calculated? (0: normal, 1: particle lifetime)\n   */\n  mixNoise?: number\n  /**\n   * Material blending\n   */\n  blending?: Blending\n  /**\n   * Material transparency\n   */\n  transparent?: boolean\n  /**\n   * Material depth write\n   */\n  depthWrite?: boolean\n}\n\nconst props = withDefaults(defineProps<SparkleProps>(), {\n  map: 'https://raw.githubusercontent.com/Tresjs/assets/'\n    + 'e41a93c56ec7cb5ac2d241f309e23582a5fe1fc6/textures/sparkles/particle.png',\n  geometry: undefined,\n  directionalLight: undefined,\n\n  lifetimeSec: 0.4,\n  cooldownSec: 2.0,\n\n  size: 1.0,\n  alpha: 1.0,\n  offset: 1.0,\n  noiseScale: 3.0,\n  surfaceDistance: 1.0,\n\n  scaleNoise: 1.0,\n  offsetNoise: 0.1,\n  lifetimeNoise: 0.0,\n\n  normalThreshold: 0.7,\n\n  sequenceColor: () => [[0.7, '#82dbc5'], [0.8, '#fbb03b']],\n  sequenceAlpha: () => [[0.0, 0.0], [0.10, 1.0], [0.5, 1.0], [0.9, 0.0]],\n  sequenceOffset: () => [0.0, 0.0, 0.0],\n  sequenceSurfaceDistance: () => [0.05, 0.08, 0.1],\n  sequenceSize: () => [0.0, 1.0],\n  sequenceNoise: () => [0.1, 0.1, 0.1],\n\n  mixColor: 0.5,\n  mixAlpha: 1.0,\n  mixOffset: 1.0,\n  mixSize: 0.0,\n  mixSurfaceDistance: 1.0,\n  mixNoise: 1.0,\n\n  blending: AdditiveBlending,\n  transparent: true,\n  depthWrite: false,\n})\n\nconst version = Number.parseInt(REVISION.replace(/\\D+/g, ''))\n\nconst refs = toRefs(props)\nconst map: Texture = typeof props.map === 'string' ? useEmptyDataTexture() : props.map\nconst { texture: infoTexture, yFor } = new ShaderDataBuilder(256)\n  .add\n  .GradientTresColor(refs.sequenceColor)\n  .id('sequenceColor')\n  .add\n  .Gradient01(refs.sequenceAlpha)\n  .id('sequenceAlpha')\n  .add\n  .Gradient01(refs.sequenceSurfaceDistance)\n  .id('sequenceSurfaceDistance')\n  .add\n  .Gradient01(refs.sequenceSize)\n  .id('sequenceSize')\n  .add\n  .GradientXyz(refs.sequenceOffset, -1, 1)\n  .id('sequenceOffset')\n  .add\n  .GradientXyz(refs.sequenceNoise, 0, 1)\n  .id('sequenceNoise')\n  .build()\n  .useTexture()\n\nconst shaderMaterialParameters: ShaderMaterialParameters = {\n  blending: props.blending,\n  transparent: props.transparent,\n  depthWrite: props.depthWrite,\n  uniforms: {\n    uMap: new Uniform(map),\n    uPixelRatio: new Uniform(1),\n    uNormal: new Uniform(Object3D.DEFAULT_UP),\n    uNormalThreshold: new Uniform(props.normalThreshold),\n    uTime: new Uniform(0),\n    uCooldownRatio: new Uniform(1),\n    uSize: new Uniform(props.size),\n    uAlpha: new Uniform(props.alpha),\n    uOffset: new Uniform(props.offset),\n    uSurfaceDistance: new Uniform(props.surfaceDistance),\n    uNoiseScale: new Uniform(props.noiseScale),\n    uScaleNoise: new Uniform(props.scaleNoise),\n    uOffsetNoise: new Uniform(props.offsetNoise),\n    uLifetimeNoise: new Uniform(props.lifetimeNoise),\n    uMixColor: new Uniform(props.mixColor),\n    uMixAlpha: new Uniform(props.mixAlpha),\n    uMixOffset: new Uniform(props.mixOffset),\n    uMixSize: new Uniform(props.mixSize),\n    uMixSurfaceDistance: new Uniform(props.mixSurfaceDistance),\n    uMixNoise: new Uniform(props.mixNoise),\n    uInfoTexture: new Uniform(infoTexture.value),\n  },\n  vertexShader: `\n    uniform float uPixelRatio;\n    uniform vec3 uNormal;\n    uniform float uNormalThreshold;\n    uniform float uTime;\n    uniform float uCooldownRatio;\n    uniform float uSize;\n    uniform float uAlpha;\n    uniform float uOffset;\n    uniform float uSurfaceDistance;\n    uniform float uNoiseScale;\n    uniform float uScaleNoise;\n    uniform float uOffsetNoise;\n    uniform float uLifetimeNoise;\n    uniform float uMixColor;\n    uniform float uMixAlpha;\n    uniform float uMixOffset;\n    uniform float uMixSize;\n    uniform float uMixSurfaceDistance;\n    uniform float uMixNoise;\n    uniform sampler2D uInfoTexture;\n\n    varying vec4 vColor;\n\n    void main() {\n      float dotNormal = dot(normal, uNormal) * 0.5 + 0.5;\n      float normalP = smoothstep(uNormalThreshold, 1., dotNormal);\n      float lifetimeNoise = uLifetimeNoise * mix(normalP, 1.0, uMixNoise);\n\n      float t = uTime + position.x * 1. * uNoiseScale + position.y * 10. * uNoiseScale + \n      position.z * 7.3 * uNoiseScale + sin(lifetimeNoise * (position.x + 13. * position.y)) * lifetimeNoise;\n\n      float lifetimeP = max(-0.0001, mix(-uCooldownRatio, 1. + cos(t) * lifetimeNoise, fract(t)));\n      float surfaceDistance = texture2D(uInfoTexture, vec2(\n        mix(normalP, lifetimeP, uMixSurfaceDistance),\n        ${yFor.sequenceSurfaceDistance})).x * uSurfaceDistance;\n\n      vec4 modelPosition = modelMatrix * (vec4(position, 1.0) + vec4(normal * surfaceDistance, 0.0));\n      vec3 noise = texture2D(uInfoTexture, vec2(\n        mix(normalP, lifetimeP, uMixNoise),\n        ${yFor.sequenceNoise})).xyz;\n      vec3 offset = uOffset * (texture2D(uInfoTexture, vec2(\n        mix(normalP, lifetimeP, uMixOffset),\n        ${yFor.sequenceOffset})).xyz * 2.0 - vec3(1.0, 1.0, 1.0));\n      modelPosition.x += cos(t * uNoiseScale * 10.0) * 0.2 * uOffsetNoise * noise.x + offset.x;\n      modelPosition.y += sin(t * uNoiseScale * 10.0) * 0.2 * uOffsetNoise * noise.y + offset.y;\n      modelPosition.z += cos(t * uNoiseScale * 10.0) * 0.2 * uOffsetNoise * noise.z + offset.z;\n\n      vec4 viewPosition = viewMatrix * modelPosition;\n      vec4 projectionPostion = projectionMatrix * viewPosition;\n      gl_Position = projectionPostion;\n\n      gl_PointSize = 2.\n      * texture2D(uInfoTexture, vec2(mix(normalP, lifetimeP, uMixSize), ${yFor.sequenceSize})).x\n      * mix(1., abs(sin(t * uNoiseScale + position.x * 13.9 + position.y * 73.1)), uScaleNoise)\n      * uSize * (100.0 / -viewPosition.z) * uPixelRatio;\n\n      if (gl_PointSize < 0.6 || lifetimeP < 0.0) { gl_Position = vec4(2, 2, 2, 1); }\n\n      vColor = texture2D(uInfoTexture, vec2(mix(normalP, lifetimeP, uMixColor), ${yFor.sequenceColor}))\n      * texture2D(uInfoTexture, vec2(mix(normalP, lifetimeP, uMixAlpha), ${yFor.sequenceAlpha})).x * uAlpha;\n    }`,\n  fragmentShader: `\n    varying vec4 vColor;\n\n    uniform sampler2D uMap;\n    uniform sampler2D uInfoTexture;\n\n    void main() {\n      gl_FragColor = vColor * texture2D(uMap, gl_PointCoord);\n      #include <tonemapping_fragment>\n      #include <${version >= 154 ? 'colorspace_fragment' : 'encodings_fragment'}>\n    }`,\n}\n\nconst mat = new ShaderMaterial(shaderMaterialParameters)\nconst sparkles = new Points(undefined, mat)\n\ndefineExpose({ instance: sparkles })\n\nconst u = mat.uniforms\nconst NOW = { immediate: true }\n\nconst uniformsRefs: [IUniform, Ref][] = [\n  [u.uPixelRatio, useTresContext().sizes.aspectRatio],\n  [u.uSize, refs.size],\n  [u.uNormalThreshold, refs.normalThreshold],\n  [u.uAlpha, refs.alpha],\n  [u.uOffset, refs.offset],\n  [u.uOffsetNoise, refs.offsetNoise],\n  [u.uMixColor, refs.mixColor],\n  [u.uMixAlpha, refs.mixAlpha],\n  [u.uMixOffset, refs.mixOffset],\n  [u.uMixSize, refs.mixSize],\n  [u.uMixSurfaceDistance, refs.mixSurfaceDistance],\n  [u.uMixNoise, refs.mixNoise],\n  [u.uInfoTexture, infoTexture],\n]\n\nuniformsRefs.forEach(\n  ([uniform, ref]) => watch(\n    ref,\n    () => { uniform.value = ref.value },\n    NOW,\n  ),\n)\n\nwatch([refs.noiseScale, refs.lifetimeSec], () => {\n  // NOTE: Scale noise by lifetime so that scaling lifetime keeps same noise period\n  u.uNoiseScale.value = refs.noiseScale.value * refs.lifetimeSec.value\n}, NOW)\n\nwatch([refs.lifetimeSec, refs.cooldownSec], () => { u.uCooldownRatio.value = refs.cooldownSec.value / refs.lifetimeSec.value }, NOW)\n\nwatch(refs.map, () => {\n  if (typeof refs.map.value === 'string') {\n    const { state: texture } = useTexture(refs.map.value)\n    mat.uniforms.uMap.value = texture\n  }\n  else {\n    mat.uniforms.uMap.value = refs.map.value\n  }\n})\n\nconst rotation = new Quaternion()\nconst normal = new Vector3()\nuseLoop().onBeforeRender(({ elapsed /* invalidate */ }) => {\n  sparkles.getWorldQuaternion(rotation)\n  normal.copy(props.directionalLight ? props.directionalLight.position : Object3D.DEFAULT_UP).normalize()\n  normal.applyQuaternion(rotation.invert())\n  mat.uniforms.uNormal.value = normal\n  mat.uniforms.uTime.value = elapsed / (props.cooldownSec + props.lifetimeSec)\n  // TODO: comment this until invalidate is back in the loop callback on v5\n  // invalidate()\n})\n\nfunction isObject3D(o: any): o is Object3D {\n  return o && 'isObject3D' in o\n}\n\nfunction isBufferGeometry(o: any): o is BufferGeometry {\n  return o && 'isBufferGeometry' in o\n}\n\nonMounted(() => {\n  if (props.geometry) {\n    if (isBufferGeometry(props.geometry)) {\n      sparkles.geometry.copy(props.geometry)\n    }\n    else if (isObject3D(props.geometry) && 'geometry' in props.geometry && isBufferGeometry(props.geometry.geometry)) {\n      sparkles.geometry.copy(props.geometry.geometry)\n    }\n  }\n  else if (isObject3D(sparkles.parent) && 'geometry' in sparkles.parent && isBufferGeometry(sparkles.parent.geometry)) {\n    sparkles.geometry.copy(sparkles.parent.geometry)\n  }\n  else {\n    sparkles.geometry = new IcosahedronGeometry(1, 16)\n  }\n\n  if (typeof props.map === 'string') {\n    const { state: texture } = useTexture(props.map)\n    mat.uniforms.uMap.value = texture\n  }\n})\n\nonUnmounted(() => {\n  mat.uniforms.uMap.value?.dispose()\n  infoTexture.value.dispose()\n  mat.dispose()\n})\n</script>\n\n<template>\n  <primitive :object=\"sparkles\" />\n</template>\n"
  },
  {
    "path": "src/core/staging/Sparkles/useEmptyDataTexture.ts",
    "content": "import { DataTexture } from 'three'\n\nlet texture: DataTexture | null = null\n\nexport default function useEmptyDataTexture(): DataTexture {\n  if (texture === null) {\n    texture = new DataTexture(new Uint8Array([0, 0, 0, 0]), 1, 1)\n  }\n  return texture\n}\n"
  },
  {
    "path": "src/core/staging/Stage.vue",
    "content": "<script setup lang=\"ts\">\nimport type { ComputedRef } from 'vue'\nimport { computed, ref, shallowRef, watch } from 'vue'\nimport type { Group } from 'three'\nimport { AccumulativeShadows, Align, Bounds, ContactShadows, Environment, RandomizedLights } from '.'\nimport type { AccumulativeShadowsProps } from './AccumulativeShadows/component.vue'\nimport type { ContactShadowsProps } from './ContactShadows.vue'\nimport type { RandomizedLightsProps } from './RandomizedLights/component.vue'\nimport type { AlignCallbackOptions, AlignProps } from './Align.vue'\nimport type { EnvironmentOptions, EnvironmentPresetsType } from './useEnvironment/const'\nimport { useDebounceFn } from '@vueuse/core'\n\ninterface StageProps {\n  /** Lighting setup, default: \"rembrandt\" */\n  lighting?:\n    | null | undefined | false\n    | 'rembrandt'\n    | 'portrait'\n    | 'upfront'\n    | 'soft'\n    | { main: [x: number, y: number, z: number], fill: [x: number, y: number, z: number] }\n  /** Controls the ground shadows, default: \"contact\" */\n  shadows?: boolean | 'contact' | 'accumulative' | StageShadows\n  /** Optionally wraps and thereby centers the models using <Bounds>, can also be a camera offset, default: true */\n  adjustCamera?: boolean | number\n  /** The default environment, default: { preset: \"city\" } */\n  environment?: EnvironmentPresetsType | Partial<EnvironmentOptions> | null\n  /** Lighting intensity, `0` removes lights, default: 0.5 */\n  intensity?: number\n  /** To adjust alignment, default: undefined */\n  align?: Partial<AlignProps>\n}\n\ntype StageShadows = Partial<AccumulativeShadowsProps> &\n  Partial<RandomizedLightsProps> &\n  Partial<ContactShadowsProps> & {\n    type: 'contact' | 'accumulative'\n    /** Shadow plane offset, default: 0 */\n    offset?: number\n    /** Shadow bias, default: -0.0001 */\n    bias?: number\n    /** Shadow normal bias, default: 0 */\n    normalBias?: number\n    /** Shadow map size, default: 1024 */\n    size?: number\n  }\n\nconst props = withDefaults(defineProps<StageProps>(), {\n  adjustCamera: true,\n  intensity: 0.5,\n  shadows: 'contact',\n  environment: () => ({ preset: 'city' }),\n  lighting: 'rembrandt',\n})\n\ninterface LightingPreset {\n  main: [number, number, number]\n  fill: [number, number, number]\n}\n\ninterface LightingPresets {\n  rembrandt: LightingPreset\n  portrait: LightingPreset\n  upfront: LightingPreset\n  soft: LightingPreset\n}\n\nconst lightingPresets: LightingPresets = {\n  rembrandt: {\n    main: [1, 2, 1],\n    fill: [-2, -0.5, -2],\n  },\n  portrait: {\n    main: [-1, 2, 0.5],\n    fill: [-1, 0.5, -1.5],\n  },\n  upfront: {\n    main: [0, 2, 1],\n    fill: [-1, 0.5, -1.5],\n  },\n  soft: {\n    main: [-2, 4, 4],\n    fill: [-1, 0.5, -1.5],\n  },\n}\n\nconst radius = ref(2)\nconst height = ref(0)\nconst stageRef = shallowRef<typeof Group>()\nconst boundsRef = shallowRef<typeof Bounds>()\nconst alignRef = shallowRef<typeof Align>()\nconst accumulativeShadowsRef = shallowRef<typeof AccumulativeShadows>()\n\nconst debouncedLookAt = useDebounceFn(() => {\n  if (boundsRef.value?.instance) {\n    boundsRef.value.instance.lookAt(boundsRef.value.instance)\n  }\n}, 500, { maxWait: 2000 })\n\nwatch(() => [props.adjustCamera, radius.value], () => {\n  alignRef.value?.update()\n  if (props.adjustCamera !== false && boundsRef.value) {\n    boundsRef.value.instance.offset = typeof props.adjustCamera === 'boolean' ? 0.3 : props.adjustCamera\n    debouncedLookAt()\n  }\n})\n\nwatch(() => [props.shadows], () => {\n  // NOTE: `AccumulativeShadows` can be in a mode where\n  // it renders only once, then never again without\n  // explicitly calling `update`.\n  // To help users tweaking settings, we'll call `update`\n  // when the `props.shadows` object changes.\n  accumulativeShadowsRef.value?.update()\n})\n\nconst lightingPresetComputed: ComputedRef<LightingPreset> = computed(() => {\n  let preset = lightingPresets.rembrandt\n  if (typeof props.lighting === 'string') {\n    preset = lightingPresets[props.lighting]\n  }\n  else if (props.lighting) {\n    preset = props.lighting\n  }\n  return preset\n})\n\nconst lightingMainComputed: ComputedRef<[number, number, number]> = computed(() => {\n  return lightingPresetComputed.value.main.map(v => v * radius.value) as [number, number, number]\n})\n\nconst lightingFillComputed: ComputedRef<[number, number, number]> = computed(() => {\n  return lightingPresetComputed.value.fill.map(v => v * radius.value) as [number, number, number]\n})\n\nconst contactShadowsComputed: ComputedRef<StageShadows | null> = computed(() => {\n  if (props.shadows === true || props.shadows === 'contact') {\n    return { type: 'contact' }\n  }\n  else if (typeof props.shadows === 'object' && props.shadows.type === 'contact') {\n    return props.shadows\n  }\n  else {\n    return null\n  }\n})\n\nconst accumulativeShadowsComputed: ComputedRef<StageShadows | null> = computed(() => {\n  if (props.shadows === 'accumulative') {\n    return { type: 'accumulative' }\n  }\n  else if (typeof props.shadows === 'object' && (props.shadows as StageShadows).type === 'accumulative') {\n    return props.shadows\n  }\n  else {\n    return null\n  }\n})\n\nconst environmentComputed: ComputedRef<EnvironmentOptions | null> = computed(() => {\n  if (props.environment === null) {\n    return null\n  }\n  else if (!props.environment) {\n    return { preset: 'city' }\n  }\n  else if (typeof props.environment === 'string') {\n    return { preset: props.environment }\n  }\n  else {\n    return props.environment\n  }\n})\n\nconst onAlignChange = (alignProps: AlignCallbackOptions) => {\n  radius.value = alignProps.boundingSphere.radius\n  if (props.adjustCamera !== false) {\n    debouncedLookAt()\n  }\n}\n\ndefineExpose({ instance: stageRef, update: () => {} })\n</script>\n\n<template>\n  <TresGroup ref=\"stageRef\">\n    <TresGroup v-if=\"props.lighting\">\n      <TresAmbientLight :intensity=\"intensity / 3\" />\n      <TresSpotLight\n        :penumbra=\"1\"\n        :position=\"lightingMainComputed\"\n        :intensity=\"intensity * 2\"\n        :castShadow=\"!!shadows\"\n        :shadow-bias=\"(shadows as StageShadows)?.bias ?? 0\"\n        :shadow-normalBias=\"(shadows as StageShadows)?.normalBias ?? 0\"\n        :shadow-mapSize=\"(shadows as StageShadows)?.size ?? 1024\"\n      />\n      <TresPointLight\n        :position=\"lightingFillComputed\"\n        :intensity=\"intensity\"\n      />\n    </TresGroup>\n    <Bounds\n      ref=\"boundsRef\"\n      :clip=\"!!adjustCamera\"\n      :offset=\"typeof props.adjustCamera === 'boolean' ? 0.3 : props.adjustCamera\"\n      use-mounted\n      use-resize\n      v-bind=\"props\"\n    >\n      <Align ref=\"alignRef\" v-bind=\"align\" @change=\"onAlignChange\">\n        <slot></slot>\n      </Align>\n    </Bounds>\n    <TresGroup :position=\"[0, -height / 2 - ((shadows as StageShadows)?.offset ?? 0) / 2, 0]\">\n      <ContactShadows\n        v-if=\"contactShadowsComputed\"\n        :scale=\"radius * 4\"\n        :far=\"radius\"\n        :blur=\"2\"\n        v-bind=\"contactShadowsComputed\"\n      />\n      <AccumulativeShadows\n        v-if=\"accumulativeShadowsComputed\"\n        ref=\"accumulativeShadowsRef\"\n        :frames=\"100\"\n        :alpha-test=\"0.5\"\n        :tone-mapped=\"true\"\n        :scale=\"radius * 4\"\n        v-bind=\"accumulativeShadowsComputed\"\n      >\n        <RandomizedLights\n          :position=\"lightingMainComputed\"\n          :count=\"accumulativeShadowsComputed.count ?? 8\"\n          :radius=\"accumulativeShadowsComputed.radius ?? radius\"\n          :intensity=\"accumulativeShadowsComputed.intensity ?? 1.5\"\n          :ambient=\"accumulativeShadowsComputed.ambient ?? 0.5\"\n          :size=\"radius * 4\"\n          :bias=\"accumulativeShadowsComputed.bias ?? 0\"\n          :map-size=\"accumulativeShadowsComputed.size ?? 1024\"\n          v-bind=\"accumulativeShadowsComputed\"\n        />\n      </AccumulativeShadows>\n      <Suspense>\n        <Environment v-if=\"environmentComputed\" v-bind=\"environmentComputed\" />\n      </Suspense>\n    </TresGroup>\n  </TresGroup>\n</template>\n"
  },
  {
    "path": "src/core/staging/Stars.vue",
    "content": "<script setup lang=\"ts\">\nimport { useTres } from '@tresjs/core'\nimport { Spherical, Vector3 } from 'three'\nimport { computed, ref, shallowRef, toRefs, watch, watchEffect } from 'vue'\n\nexport interface StarsProps {\n  /**\n   * The size of the stars.\n   *\n   * @type {number}\n   * @memberof StarsProps\n   * @default 0.1\n   */\n  size?: number\n  /**\n   * keep the same size regardless distance.\n   *\n   * @type {boolean}\n   * @memberof StarsProps\n   * @default true\n   */\n  sizeAttenuation?: boolean\n  /**\n   * show transparency on the stars texture.\n   *\n   * @type {boolean}\n   * @memberof StarsProps\n   * @default true\n   */\n  transparent?: boolean\n  /**\n   * enables the WebGL to know when not to render the pixel.\n   *\n   * @type {number}\n   * @memberof StarsProps\n   * @default 0.01\n   */\n  alphaTest?: number\n  /**\n   * number of stars.\n   *\n   * @type {number}\n   * @memberof StarsProps\n   * @default 5000\n   */\n  count?: number\n  /**\n   * depth of star's shape.\n   *\n   * @type {number}\n   * @memberof StarsProps\n   * @default 50\n   */\n  depth?: number\n  /**\n   * Radius of star's shape.\n   *\n   * @type {number}\n   * @memberof StarsProps\n   * @default 100\n   */\n  radius?: number\n  /**\n   * texture of the stars.\n   *\n   * @type {string}\n   * @memberof StarsProps\n   * @default null\n   */\n  alphaMap?: null\n}\n\nconst props = withDefaults(defineProps<StarsProps>(), {\n  size: 0.1,\n  sizeAttenuation: true,\n  transparent: true,\n  alphaTest: 0.01,\n  alphaMap: null,\n  count: 5000,\n  depth: 50,\n  radius: 100,\n})\n\nconst position = ref()\nconst scale = ref()\n\nconst { radius, depth, count, size, sizeAttenuation, transparent, alphaMap, alphaTest } = toRefs(props)\n\nconst { invalidate } = useTres()\n\nwatch(props, () => {\n  invalidate()\n})\n\nconst setStars = () => {\n  let circle = radius.value + depth.value\n  const increment = computed(() => depth.value / count.value)\n\n  const positionArray: number[] = []\n  const scaleArray: number[] = Array.from(\n    { length: count.value },\n    () => (0.5 + 0.5 * Math.random()) * 4,\n  )\n\n  const generateStars = (circle: number): Array<number> => {\n    const starArray = new Vector3()\n      .setFromSpherical(new Spherical(circle, Math.acos(1 - Math.random() * 2), Math.random() * 2 * Math.PI))\n      .toArray()\n    return starArray\n  }\n\n  for (let i = 0; i < count.value; i++) {\n    circle -= increment.value * Math.random()\n    positionArray.push(...generateStars(circle))\n  }\n  position.value = new Float32Array(positionArray)\n  scale.value = new Float32Array(scaleArray)\n}\n\nwatchEffect(() => {\n  setStars()\n})\n\nconst starsRef = shallowRef()\n\ndefineExpose({\n  instance: starsRef,\n})\n</script>\n\n<template>\n  <TresPoints ref=\"starsRef\">\n    <TresBufferGeometry\n      :position=\"[position, 3]\"\n      :a-scale=\"[scale, 1]\"\n    />\n    <TresPointsMaterial\n      :size=\"size\"\n      :size-attenuation=\"sizeAttenuation\"\n      :transparent=\"transparent\"\n      :alpha-test=\"alphaTest\"\n      :alpha-map=\"alphaMap\"\n    />\n  </TresPoints>\n</template>\n"
  },
  {
    "path": "src/core/staging/index.ts",
    "content": "import AccumulativeShadows from './AccumulativeShadows/component.vue'\nimport Align from './Align.vue'\nimport Backdrop from './Backdrop.vue'\nimport Bounds from './Bounds/component.vue'\nimport ContactShadows from './ContactShadows.vue'\nimport Fit from './Fit.vue'\nimport Grid from './Grid.vue'\nimport Ocean from './Ocean.vue'\nimport Precipitation from './Precipitation.vue'\nimport CircleShadow from './CircleShadow.vue'\nimport RandomizedLights from './RandomizedLights/component.vue'\nimport Sky from './Sky.vue'\nimport Smoke from './Smoke.vue'\nimport SoftShadows from './SoftShadows.vue'\nimport Sparkles from './Sparkles/component.vue'\nimport Stage from './Stage.vue'\nimport Stars from './Stars.vue'\nimport Environment from './useEnvironment/component.vue'\nimport Lightformer from './useEnvironment/lightformer/index.vue'\n\nexport {\n  AccumulativeShadows,\n  Align,\n  Backdrop,\n  Bounds,\n  CircleShadow,\n  ContactShadows,\n  Environment,\n  Fit,\n  Grid,\n  Lightformer,\n  Ocean,\n  Precipitation,\n  RandomizedLights,\n  Sky,\n  Smoke,\n  SoftShadows,\n  Sparkles,\n  Stage,\n  Stars,\n}\n"
  },
  {
    "path": "src/core/staging/useEnvironment/EnvironmentScene.ts",
    "content": "import { Mesh, Object3D, Scene } from 'three'\n\nclass EnvironmentScene extends Object3D {\n  virtualScene = null as unknown as Scene\n  constructor() {\n    super()\n    this.virtualScene = new Scene()\n  }\n\n  // @ts-expect-error - No idea how to fix the type error here\n  add(...object: Object3D[]): this {\n    for (const obj of object) {\n      this.virtualScene.add(obj)\n    }\n    return this\n  }\n\n  dispose() {\n    this.virtualScene.traverse((object) => {\n      if (object instanceof Mesh) {\n        object.geometry.dispose()\n        object.material.dispose()\n        if (object.material.map) { object.material.map.dispose() }\n        this.virtualScene.remove(object)\n      }\n    })\n    this.virtualScene = null as unknown as Scene\n  }\n}\n\nexport default EnvironmentScene\n"
  },
  {
    "path": "src/core/staging/useEnvironment/component.vue",
    "content": "<script setup lang=\"ts\">\nimport { useLoop, useTresContext } from '@tresjs/core'\nimport { BackSide, BoxGeometry, CubeCamera, HalfFloatType, Mesh, MeshBasicMaterial, WebGLCubeRenderTarget } from 'three'\nimport { onUnmounted, ref, toRaw, useSlots, watch } from 'vue'\nimport type { CubeTexture, Texture } from 'three'\nimport type { Ref } from 'vue'\nimport { useEnvironment } from '.'\nimport EnvironmentScene from './EnvironmentScene'\nimport type { EnvironmentOptions } from './const'\n\nconst props = withDefaults(defineProps<EnvironmentOptions>(), {\n  background: false,\n  blur: 0,\n  files: () => [],\n  path: '',\n  preset: undefined,\n  resolution: 256,\n  near: 1,\n  far: 1000,\n  frames: Number.POSITIVE_INFINITY,\n  backgroundIntensity: 1,\n  environmentIntensity: 1,\n})\n\nconst texture: Ref<Texture | CubeTexture | null> = ref(null)\ndefineExpose({ texture })\n\nconst { extend, renderer, scene } = useTresContext()\nextend({ EnvironmentScene })\n\nlet slots = null as any\nconst fbo = ref<WebGLCubeRenderTarget | null>(null)\nlet cubeCamera: CubeCamera | null = null\nconst environmentScene = ref<EnvironmentScene | null>(null)\n\nconst useEnvironmentTexture = await useEnvironment(props, fbo)\n\nconst { onBeforeRender } = useLoop()\nlet count = 1\n\nonBeforeRender(() => {\n  if (cubeCamera && environmentScene.value && fbo.value) {\n    if (props.frames === Number.POSITIVE_INFINITY || count < props.frames) {\n      // Update cube camera\n      const autoClear = renderer.instance.autoClear\n      renderer.instance.autoClear = true\n      // Use raw scene to avoid proxy issues\n      const rawScene = toRaw(environmentScene.value).virtualScene\n      cubeCamera.update(renderer.instance, rawScene)\n      renderer.instance.autoClear = autoClear\n      count++\n    }\n  }\n}, -1)\n\n// Add environment map to virtual scene when available\nwatch([useEnvironmentTexture, environmentScene], ([texture, scene]) => {\n  if (texture && scene?.virtualScene) {\n    const rawScene = toRaw(scene).virtualScene\n\n    // Find existing environment mesh or create a new one\n    let envMesh = rawScene.children.find(\n      child => child instanceof Mesh && child.userData.isEnvironment,\n    ) as Mesh | undefined\n\n    if (!envMesh) {\n      // Create new environment mesh if none exists\n      envMesh = new Mesh(\n        new BoxGeometry(1, 1, 1),\n        new MeshBasicMaterial({ side: BackSide }),\n      )\n      envMesh.userData.isEnvironment = true\n      rawScene.add(envMesh)\n    }\n\n    // Update the environment map\n    rawScene.background = texture\n    rawScene.backgroundBlurriness = props.blur\n  }\n}, { immediate: true })\n\nconst setTextureEnvAndBG = (fbo?: WebGLCubeRenderTarget) => {\n  if (fbo && slots?.length) {\n    // If we have lightformers, use FBO texture for both environment and background\n    scene.value.environment = fbo.texture\n    if (props.background) {\n      scene.value.background = fbo.texture\n    }\n  }\n  else if (useEnvironmentTexture.value) {\n    // Otherwise use the original environment texture\n    scene.value.environment = useEnvironmentTexture.value\n    if (props.background) {\n      scene.value.background = useEnvironmentTexture.value\n    }\n  }\n}\n\nwatch(useEnvironmentTexture, () => {\n  if (fbo.value) {\n    setTextureEnvAndBG(fbo.value)\n  }\n}, { immediate: true, deep: true })\n\nwatch(() => useSlots().default, (value) => {\n  if (value) {\n    slots = value()\n    if (Array.isArray(slots) && slots.length > 0) {\n      extend({ EnvironmentScene })\n      fbo.value = new WebGLCubeRenderTarget(props.resolution)\n      fbo.value.texture.type = HalfFloatType\n      cubeCamera = new CubeCamera(props.near, props.far, fbo.value)\n      setTextureEnvAndBG(fbo.value)\n      return\n    }\n  }\n  fbo.value?.dispose()\n  fbo.value = null\n  setTextureEnvAndBG()\n}, { immediate: true, deep: true })\n\ntexture.value = useEnvironmentTexture.value\n\nonUnmounted(() => {\n  environmentScene.value?.dispose()\n  fbo.value?.dispose()\n})\n</script>\n\n<template>\n  <TresEnvironmentScene\n    v-if=\"fbo\"\n    ref=\"environmentScene\"\n  >\n    <slot></slot>\n  </TresEnvironmentScene>\n</template>\n"
  },
  {
    "path": "src/core/staging/useEnvironment/const.ts",
    "content": "import type { VectorFlexibleParams } from '@tresjs/core'\n\nexport interface EnvironmentOptions {\n  /**\n   * If true, the environment will be set as the scene's background.\n   *\n   * @type {boolean}\n   * @default false\n   */\n  background?: boolean | string\n  /**\n   * The blur radius of the environment.\n   *\n   * @type {number}\n   * @default 0\n   */\n  blur?: number\n  /**\n   * The files to load. If a string is provided, it will be loaded as an equirectangular texture.\n   * If an array is provided, it will be loaded as a cube texture.\n   *\n   * @type {(string | string[])}\n   */\n  files?: string | string[]\n  /**\n   * The path to the files.\n   *\n   * @type {string}\n   * @default '/'\n   */\n  path?: string\n  /**\n   * The preset to use. If provided, the files and path props will be ignored.\n   *\n   * @type {EnvironmentPresetsType}\n   */\n  preset?: EnvironmentPresetsType\n  /**\n   * The resolution of the WebGLCubeRenderTarget.\n   *\n   * @type {number}\n   * @default 256\n   */\n  resolution?: number\n  /**\n   * The near of the CubeCamera.\n   *\n   * @type {number}\n   * @default 1\n   */\n  near?: number\n  /**\n   * The far of the CubeCamera.\n   *\n   * @type {number}\n   * @default 1000\n   */\n  far?: number\n  /**\n   * The frames of the cubeCamera.update.\n   *\n   * @type {number}\n   * @default Infinity\n   */\n  frames?: number\n  /**\n   * The intensity of the background.\n   *\n   * @type {number}\n   * @default 1\n   */\n  backgroundIntensity?: number\n  /**\n   * The rotation of the background.\n   *\n   * @type {VectorFlexibleParams}\n   * @default [0, 0, 0]\n   */\n  backgroundRotation?: VectorFlexibleParams\n  /**\n   * The intensity of the environment.\n   *\n   * @type {number}\n   * @default 1\n   */\n  environmentIntensity?: number\n  /**\n   * The rotation of the environment.\n   *\n   * @type {VectorFlexibleParams}\n   * @default [0, 0, 0]\n   */\n  environmentRotation?: VectorFlexibleParams\n  /**\n   * If true, the environment rotation will be synced with the background rotation.\n   * This means when backgroundRotation changes, environmentRotation will be updated to match.\n   *\n   * @type {boolean}\n   * @default false\n   */\n  syncMaterials?: boolean\n}\n\nexport const environmentPresets = {\n  sunset: 'venice/venice_sunset_1k.hdr',\n  studio: 'studio/poly_haven_studio_1k.hdr',\n  city: 'city/canary_wharf_1k.hdr',\n  umbrellas: 'outdoor/outdoor_umbrellas_1k.hdr',\n  night: 'outdoor/satara_night_1k.hdr',\n  forest: 'outood/mossy_forest_1k.hdr',\n  snow: 'outdoor/snowy_forest_path_01_1k.hdr',\n  dawn: 'kiara/kiara_1_dawn_1k.hdr',\n  hangar: 'indoor/small_hangar_01_1k.hdr',\n  urban: 'indoor/abandoned_games_room_02_1k.hdr',\n  modern: 'city/modern_buildings_2_1k.hdr',\n  shangai: 'city/shanghai_bund_1k.hdr',\n}\n\nexport type EnvironmentPresetsType = keyof typeof environmentPresets\n"
  },
  {
    "path": "src/core/staging/useEnvironment/index.ts",
    "content": "import { useTres } from '@tresjs/core'\nimport {\n  CubeReflectionMapping,\n  CubeTextureLoader,\n  EquirectangularReflectionMapping,\n  Euler,\n  Mesh,\n  Vector3,\n} from 'three'\nimport { RGBELoader } from 'three-stdlib'\nimport { computed, ref, toRefs, unref, watch } from 'vue'\nimport type {\n  CubeTexture,\n  Scene,\n  Texture,\n  WebGLCubeRenderTarget,\n} from 'three'\nimport type { Ref } from 'vue'\nimport { environmentPresets } from './const'\nimport type { EnvironmentOptions } from './const'\n\nconst PRESET_ROOT = 'https://raw.githubusercontent.com/Tresjs/assets/main/textures/hdr/'\n\n/**\n * Converts various rotation formats to an Euler instance\n * @param value - The rotation value to convert\n * @returns An Euler instance or null if conversion fails\n */\nfunction toEuler(value: any): Euler | null {\n  if (value instanceof Euler) {\n    return value\n  }\n  if (Array.isArray(value)) {\n    return new Euler(value[0], value[1], value[2])\n  }\n  if (typeof value === 'number') {\n    return new Euler(value, value, value)\n  }\n  if (value instanceof Vector3) {\n    return new Euler(value.x, value.y, value.z)\n  }\n  if (typeof value === 'object' && 'x' in value && 'y' in value && 'z' in value) {\n    return new Euler(value.x, value.y, value.z)\n  }\n  return null\n}\n\n/**\n * Updates all materials in the scene\n * @param scene - The scene to update\n */\nfunction updateMaterials(scene: Scene) {\n  scene.traverse((child) => {\n    if (child instanceof Mesh && child.material) {\n      child.material.needsUpdate = true\n    }\n  })\n}\n\n/**\n * Component that loads an environment map and sets it as the scene's background and environment.\n *\n * @export\n * @param {Partial<EnvironmentOptions>} options - The options for the environment map\n *   files = ['/px.png', '/nx.png', '/py.png', '/ny.png', '/pz.png', '/nz.png'],\n *   blur = 0,\n *   background = false,\n *   path = undefined,\n *   preset = undefined,\n *   colorSpace = 'srgb',\n *   backgroundIntensity = 1,\n *   environmentIntensity = 1,\n *   backgroundRotation = [0, 0, 0],\n *   environmentRotation = [0, 0, 0],\n *   syncMaterials = false,\n * @param {Ref<WebGLCubeRenderTarget | null>} fbo - The framebuffer object\n * @return {Promise<Ref<Texture | CubeTexture | null>>} The loaded texture\n */\nexport async function useEnvironment(\n  options: Partial<EnvironmentOptions>,\n  fbo: Ref<WebGLCubeRenderTarget | null>,\n): Promise<Ref<Texture | CubeTexture | null>> {\n  const { scene, invalidate } = useTres()\n\n  const {\n    preset,\n    blur,\n    files = ref([]),\n    path = ref(''),\n    background,\n    backgroundIntensity = ref(1),\n    environmentIntensity = ref(1),\n    backgroundRotation = ref([0, 0, 0]),\n    environmentRotation = ref([0, 0, 0]),\n    syncMaterials = ref(false),\n  } = toRefs(options)\n\n  watch(options, () => {\n    invalidate()\n  })\n\n  const texture: Ref<Texture | CubeTexture | null> = ref(null)\n  const isCubeMap = computed(() => Array.isArray((files as Ref<string[]>).value))\n\n  // Create loaders\n  const cubeTextureLoader = new CubeTextureLoader()\n  const rgbeLoader = new RGBELoader()\n\n  // Function to load textures directly\n  const loadTexture = async (files: string[], path?: string): Promise<Texture | CubeTexture> => {\n    return new Promise((resolve, reject) => {\n      if (isCubeMap.value) {\n        // Handle cube map\n        if (path) { cubeTextureLoader.setPath(path) }\n        cubeTextureLoader.load(\n          files,\n          (texture) => {\n            texture.mapping = CubeReflectionMapping\n            resolve(texture)\n          },\n          undefined,\n          error => reject(error),\n        )\n      }\n      else {\n        // Handle HDR/equirectangular\n        if (path) { rgbeLoader.setPath(path) }\n        rgbeLoader.load(\n          files[0],\n          (texture) => {\n            texture.mapping = EquirectangularReflectionMapping\n            resolve(texture)\n          },\n          undefined,\n          error => reject(error),\n        )\n      }\n    })\n  }\n\n  // Watch for texture loading\n  watch([files, path], async ([files, path]) => {\n    if (!files || files.length === 0 || preset?.value) { return }\n\n    try {\n      const loadedTexture = await loadTexture(\n        isCubeMap.value\n          ? [...(unref(files) as string[])]\n          : [unref(files) as string],\n        unref(path),\n      )\n      texture.value = loadedTexture\n    }\n    catch (error) {\n      throw new Error(`Failed to load environment map: ${error}`)\n    }\n  }, {\n    immediate: true,\n  })\n\n  // Watch for texture changes\n  watch(texture, (value) => {\n    if (scene.value && value) {\n      scene.value.environment = value\n    }\n  }, {\n    immediate: true,\n  })\n\n  // Watch for background changes\n  watch([background, texture], ([background, texture]) => {\n    if (scene.value) {\n      const bTexture = fbo?.value ? fbo.value.texture : texture\n      if (bTexture) {\n        scene.value.background = background ? bTexture as Texture : null\n      }\n    }\n  }, {\n    immediate: true,\n  })\n\n  // Watch for blur changes\n  watch(() => blur?.value, (value) => {\n    if (scene.value && value) {\n      scene.value.backgroundBlurriness = value\n    }\n  }, {\n    immediate: true,\n  })\n\n  // Watch for intensity changes\n  watch(() => backgroundIntensity?.value, (value) => {\n    if (scene.value) {\n      scene.value.backgroundIntensity = value ?? 1\n    }\n  }, {\n    immediate: true,\n  })\n\n  watch(() => environmentIntensity?.value, (value) => {\n    if (scene.value) {\n      scene.value.environmentIntensity = value ?? 1\n    }\n  }, {\n    immediate: true,\n  })\n\n  // Watch for background rotation changes\n  watch(() => backgroundRotation?.value, (value) => {\n    if (scene.value) {\n      const euler = toEuler(value)\n      if (euler) {\n        scene.value.backgroundRotation = euler\n      }\n    }\n  }, {\n    immediate: true,\n  })\n\n  // Watch for environment rotation changes\n  watch(() => environmentRotation?.value, (value) => {\n    if (scene.value && !syncMaterials?.value) {\n      const euler = toEuler(value)\n      if (euler) {\n        scene.value.environmentRotation = euler\n        updateMaterials(scene.value)\n      }\n    }\n  }, {\n    immediate: true,\n  })\n\n  // Watch for preset changes\n  watch(() => preset?.value, async (value) => {\n    if (value && value in environmentPresets) {\n      const _path = PRESET_ROOT\n      const _files = environmentPresets[value as unknown as keyof typeof environmentPresets]\n\n      try {\n        // Load preset using RGBELoader directly\n        rgbeLoader.setPath(_path)\n        const loadedTexture = await new Promise<Texture>((resolve, reject) => {\n          rgbeLoader.load(\n            _files,\n            (texture) => {\n              texture.mapping = EquirectangularReflectionMapping\n              resolve(texture)\n            },\n            undefined,\n            error => reject(error),\n          )\n        })\n\n        texture.value = loadedTexture\n        invalidate()\n      }\n      catch (error) {\n        throw new Error(`Failed to load environment map: ${error}`)\n      }\n      if (texture.value) {\n        texture.value.mapping = EquirectangularReflectionMapping\n      }\n      invalidate()\n    }\n    else if (value && !(value in environmentPresets)) {\n      throw new Error(`Preset must be one of: ${Object.keys(environmentPresets).join(', ')}`)\n    }\n  }, {\n    immediate: true,\n  })\n\n  // Watch for sync materials changes\n  watch([syncMaterials, backgroundRotation], ([sync, bgRotation]) => {\n    if (sync && scene.value) {\n      const euler = toEuler(bgRotation)\n      if (euler) {\n        scene.value.environmentRotation = euler\n        updateMaterials(scene.value)\n      }\n    }\n  }, {\n    immediate: true,\n  })\n\n  return texture\n}\n"
  },
  {
    "path": "src/core/staging/useEnvironment/lightformer/index.vue",
    "content": "<script setup lang=\"ts\">\nimport { Color, DoubleSide } from 'three'\n/*\n** This section of code is inspired by the Lightformer component from the drei library:\n** https://github.com/pmndrs/drei/blob/master/src/core/Lightformer.tsx\n** The Lightformer component in drei provides functionality for creating light probes in a scene.\n*/\nimport { ref, watchEffect } from 'vue'\nimport type { MeshBasicMaterial, Texture } from 'three'\n\nconst props = withDefaults(defineProps<{\n  args?: any[]\n  form?: 'circle' | 'ring' | 'rect' | any\n  toneMapped?: boolean\n  map?: Texture\n  intensity?: number\n  color?: any\n}>(), {\n  args: null as any,\n  form: 'rect',\n  toneMapped: false,\n  map: null as any,\n  intensity: 1,\n  color: new Color(0xFFFFFF),\n})\n\nconst material = ref<MeshBasicMaterial>()\nconst mesh = ref()\n\nwatchEffect(() => {\n  if (material.value) {\n    // Reset color before applying intensity to avoid accumulation\n    material.value.color.copy(new Color(props.color))\n    material.value.color.multiplyScalar(props.intensity)\n    material.value.needsUpdate = true\n  }\n})\n\n// Expose mesh for parent components\ndefineExpose({ mesh })\n</script>\n\n<template>\n  <TresMesh ref=\"mesh\">\n    <TresRingGeometry\n      v-if=\"form === 'circle'\"\n      :args=\"[0, 1, 64]\"\n    />\n    <TresRingGeometry\n      v-else-if=\"form === 'ring'\"\n      :args=\"[0.5, 1, 64]\"\n    />\n    <TresPlaneGeometry v-else-if=\"form === 'rect'\" />\n    <props.form\n      v-else\n      :args=\"args\"\n    />\n\n    <TresMeshBasicMaterial\n      ref=\"material\"\n      :tone-mapped=\"toneMapped\"\n      :map=\"map\"\n      :side=\"DoubleSide\"\n      :color=\"color\"\n    />\n  </TresMesh>\n</template>\n"
  },
  {
    "path": "src/index.ts",
    "content": "export * from './core'\nexport * from './utils'\n"
  },
  {
    "path": "src/utils/Gradient.ts",
    "content": "import { normalizeColor, normalizeVectorFlexibleParam } from '@tresjs/core'\nimport { Color } from 'three'\nimport type { TresColor, VectorFlexibleParams } from '@tresjs/core'\n\nexport type Gradient<T> = T | T[] | NormalizedGradient<T>\nexport type NormalizedGradient<T> = [number, T][]\nexport type GradientTresColor = Gradient<TresColor>\nexport type GradientScalar = Gradient<number>\nexport type GradientVectorFlexibleParams = Gradient<VectorFlexibleParams>\n\nexport function normalizeColorGradient(\n  gradient: GradientTresColor,\n): NormalizedGradient<Color> {\n  return normalizeGradient<TresColor, Color>(gradient, {\n    normalizeValue: (input: TresColor) => normalizeColor(input),\n    getDefaultValue: () => new Color(0, 0, 0),\n    isSingleValue: (t: typeof gradient) => !Array.isArray(t),\n    isMultipleValues: (t: typeof gradient) =>\n      Array.isArray(t) && (t.length === 0 || !Array.isArray(t[0])),\n    isMultipleValuesWithStops: (t: typeof gradient) =>\n      Array.isArray(t) && t.length > 0 && Array.isArray(t[0]),\n    isEmpty: (t: typeof gradient) => Array.isArray(t) && t.length === 0,\n  })\n}\n\nfunction isVectorFlexibleParams(p: any) {\n  return (\n    'isVector3' in p\n    || (Array.isArray(p) && p.length > 0 && p.every(v => typeof v === 'number'))\n  )\n}\n\nexport function normalizeFlexibleVector3Gradient(\n  gradient: GradientVectorFlexibleParams,\n) {\n  return normalizeGradient<VectorFlexibleParams, Array<number>>(gradient, {\n    normalizeValue: (input: VectorFlexibleParams) =>\n      normalizeVectorFlexibleParam(input),\n    getDefaultValue: () => [0, 0, 0],\n    isSingleValue: (t: typeof gradient) => isVectorFlexibleParams(t),\n    isMultipleValues: (t: typeof gradient) =>\n      Array.isArray(t) && t.length > 0 && isVectorFlexibleParams(t[0]),\n    isMultipleValuesWithStops: (t: typeof gradient) =>\n      Array.isArray(t)\n      && t.length > 0\n      && Array.isArray(t[0])\n      && t[0].length === 2\n      && isVectorFlexibleParams(t[0][1]),\n    isEmpty: (t: typeof gradient) => Array.isArray(t) && t.length === 0,\n  })\n}\nexport function normalizeScalarGradient(\n  gradient: GradientScalar,\n): NormalizedGradient<number> {\n  return normalizeGradient<number, number>(gradient, {\n    normalizeValue: (input: number) => input,\n    getDefaultValue: () => 1,\n    isSingleValue: (t: typeof gradient) =>\n      !Array.isArray(t) && typeof t !== 'undefined',\n    isMultipleValues: (t: typeof gradient) =>\n      Array.isArray(t) && (t.length === 0 || !Array.isArray(t[0])),\n    isMultipleValuesWithStops: (t: typeof gradient) =>\n      Array.isArray(t) && t.length > 0 && Array.isArray(t[0]),\n    isEmpty: (t: typeof gradient) => Array.isArray(t) && t.length === 0,\n  })\n}\n\ninterface NormalizeConfig<U, T> {\n  normalizeValue: (t: T) => U\n  getDefaultValue: () => U\n  isSingleValue: (t: Gradient<T>) => boolean\n  isMultipleValues: (t: Gradient<T>) => boolean\n  isMultipleValuesWithStops: (t: Gradient<T>) => boolean\n  isEmpty: (t: Gradient<T>) => boolean\n}\n\nfunction normalizeGradient<T, U>(\n  gradient: Gradient<T>,\n  config: NormalizeConfig<U, T>,\n): NormalizedGradient<U> {\n  const { normalizeValue, getDefaultValue, isEmpty } = config\n  const isSingleValue = (t: Gradient<T>): t is T => config.isSingleValue(t)\n  const isMultipleValues = (t: Gradient<T>): t is T[] =>\n    config.isMultipleValues(t)\n  const isMultipleValuesWithStops = (t: Gradient<T>): t is Array<[number, T]> =>\n    config.isMultipleValuesWithStops(t)\n\n  if (isEmpty(gradient)) {\n    return [[0, getDefaultValue()]]\n  }\n  else if (isSingleValue(gradient)) {\n    return [[0, normalizeValue(gradient as T)]]\n  }\n  else if (isMultipleValues(gradient)) {\n    const step = gradient.length > 1 ? 1 / (gradient.length - 1) : 1\n    return gradient.map((input, i) => [step * i, normalizeValue(input)])\n  }\n  else if (isMultipleValuesWithStops(gradient)) {\n    return gradient.map(([u, v], _) => [u, normalizeValue(v)])\n  }\n\n  return [[0, getDefaultValue()]]\n}\n"
  },
  {
    "path": "src/utils/calculateScaleFactor.ts",
    "content": "import * as THREE from 'three'\n\n// NOTE: Source\n// https://github.com/pmndrs/drei/blob/f8e5653f7f60d3782301c13e781c9966370b8fda/src/core/calculateScaleFactor.ts#L24\n\nconst tV0 = new THREE.Vector3()\nconst tV1 = new THREE.Vector3()\nconst tV2 = new THREE.Vector3()\n\ninterface Size {\n  width: number\n  height: number\n}\n\nconst getPoint2 = (point3: THREE.Vector3, camera: THREE.Camera, size: Size) => {\n  const widthHalf = size.width / 2\n  const heightHalf = size.height / 2\n  camera.updateMatrixWorld(false)\n  const vector = point3.project(camera)\n  vector.x = vector.x * widthHalf + widthHalf\n  vector.y = -(vector.y * heightHalf) + heightHalf\n  return vector\n}\n\nconst getPoint3 = (point2: THREE.Vector3, camera: THREE.Camera, size: Size, zValue: number = 1) => {\n  const vector = tV0.set((point2.x / size.width) * 2 - 1, -(point2.y / size.height) * 2 + 1, zValue)\n  vector.unproject(camera)\n  return vector\n}\n\nexport const calculateScaleFactor = (point3: THREE.Vector3, radiusPx: number, camera: THREE.Camera, size: Size) => {\n  const point2 = getPoint2(tV2.copy(point3), camera, size)\n  let scale = 0\n  for (let i = 0; i < 2; ++i) {\n    const point2off = tV1.copy(point2).setComponent(i, point2.getComponent(i) + radiusPx)\n    const point3off = getPoint3(point2off, camera, size, point2off.z)\n    scale = Math.max(scale, point3.distanceTo(point3off))\n  }\n  return scale\n}\n"
  },
  {
    "path": "src/utils/constants.ts",
    "content": "import { REVISION } from 'three'\n\nconst getVersion = () => Number.parseInt(REVISION.replace(/\\D+/g, ''))\n\nexport const version = /* @__PURE__ */ getVersion()\n"
  },
  {
    "path": "src/utils/easing.ts",
    "content": "export function linear(x: number): number {\n  return x\n}\n\nexport function easeInCubic(x: number): number {\n  return x * x * x\n}\n\nexport function easeInOutCubic(x: number): number {\n  return x < 0.5 ? 4 * x * x * x : 1 - ((-2 * x + 2) ** 3) / 2\n}\n\nexport function easeInQuart(x: number): number {\n  return x * x * x * x\n}\n\nexport function easeOutBounce(x: number): number {\n  const n1 = 7.5625\n  const d1 = 2.75\n\n  if (x < 1 / d1) {\n    return n1 * x * x\n  }\n  else if (x < 2 / d1) {\n    return n1 * (x -= 1.5 / d1) * x + 0.75\n  }\n  else if (x < 2.5 / d1) {\n    return n1 * (x -= 2.25 / d1) * x + 0.9375\n  }\n  else {\n    return n1 * (x -= 2.625 / d1) * x + 0.984375\n  }\n}\n"
  },
  {
    "path": "src/utils/index.ts",
    "content": "import { Vector3 } from 'three'\n\n/**\n * Update the function signature to explicitly specify the type of the props parameter\n *\n * @export\n * @template T\n * @template K\n * @param {T} obj\n * @param {K[]} props\n * @return {*}  {Pick<T, K>}\n */\nexport function pick<T extends object, K extends keyof T>(obj: T, props: K[]): Pick<T, K> {\n  const pickedProperties = {} as Pick<T, K>\n  for (const prop of props) {\n    if (Object.prototype.hasOwnProperty.call(obj, prop)) {\n      pickedProperties[prop] = obj[prop]\n    }\n  }\n  return pickedProperties\n}\n\n/**\n * Check if the object has a setter for the given property\n *\n * @export\n * @param {*} obj\n * @param {string} prop\n * @return {*}  {boolean}\n */\nexport function hasSetter(obj: any, prop: string): boolean {\n  const setterName = `set${prop[0].toUpperCase()}${prop.slice(1)}`\n  return obj[setterName] !== undefined\n}\n\nexport function extractBindingPosition(binding: any): Vector3 {\n  let observer = binding.value\n  if (binding.value && binding.value?.value?.isMesh) {\n    observer = binding.value.value.position\n  }\n  if (Array.isArray(binding.value)) { observer = new Vector3(...observer) }\n  return observer\n}\n"
  },
  {
    "path": "src/utils/shaderMaterial.ts",
    "content": "/*\nMIT License\n\nCopyright (c) 2020 react-spring\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n*/\n\nimport type { Color, CubeTexture, Matrix3, Matrix4, Quaternion, Texture, Vector2, Vector3, Vector4 } from 'three'\nimport { MathUtils, ShaderMaterial, UniformsUtils } from 'three'\n\nexport function shaderMaterial(\n  uniforms: {\n    [name: string]:\n      | CubeTexture\n      | Texture\n      | Int32Array\n      | Float32Array\n      | Matrix4\n      | Matrix3\n      | Quaternion\n      | Vector4\n      | Vector3\n      | Vector2\n      | Color\n      | number\n      | boolean\n      | Array<any>\n      | null\n  },\n  vertexShader: string,\n  fragmentShader: string,\n  onInit?: (material?: ShaderMaterial) => void,\n) {\n  const material = class extends ShaderMaterial {\n    public key: string = ''\n    constructor(parameters = {}) {\n      const entries = Object.entries(uniforms)\n      // Create unforms and shaders\n      super({\n        uniforms: entries.reduce((acc, [name, value]) => {\n          const uniform = UniformsUtils.clone({ [name]: { value } })\n          return {\n            ...acc,\n            ...uniform,\n          }\n        }, {}),\n        vertexShader,\n        fragmentShader,\n      })\n      // Create getter/setters\n      entries.forEach(([name]) =>\n        Object.defineProperty(this, name, {\n          get: () => this.uniforms[name].value,\n          set: v => (this.uniforms[name].value = v),\n        }),\n      )\n\n      // Assign parameters, this might include uniforms\n      Object.assign(this, parameters)\n      // Call onInit\n      if (onInit) { onInit(this) }\n    }\n  } as unknown as typeof ShaderMaterial & { key: string }\n  material.key = MathUtils.generateUUID()\n  return material\n}\n"
  },
  {
    "path": "src/utils/types.ts",
    "content": "import type { Camera, OrthographicCamera, PerspectiveCamera } from 'three'\n\nexport const isPerspectiveCamera = (camera?: Camera): camera is PerspectiveCamera =>\n  Boolean(camera && (camera as PerspectiveCamera).isPerspectiveCamera)\n\nexport const isOrthographicCamera = (camera?: Camera): camera is OrthographicCamera =>\n  Boolean(camera && (camera as OrthographicCamera).isOrthographicCamera)\n"
  },
  {
    "path": "src/vite-env.d.ts",
    "content": "/// <reference types=\"vite/client\" />\n\ndeclare module '*.vue' {\n  import type { DefineComponent } from 'vue'\n\n  const component: DefineComponent<unknown, unknown, any>\n  export default component\n}\n\ndeclare module '*.glsl' {}\ndeclare module '*.json' {}\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"incremental\": false,\n    \"target\": \"esnext\",\n    \"jsx\": \"preserve\",\n    \"lib\": [\"esnext\", \"dom\"],\n    \"baseUrl\": \".\",\n    \"module\": \"esnext\",\n\n    /* Bundler mode */\n    \"moduleResolution\": \"bundler\",\n    \"resolveJsonModule\": true,\n\n    \"types\": [\"vite/client\", \"node\"],\n    \"allowImportingTsExtensions\": true,\n\n    /* Linting */\n    \"strict\": true,\n    \"noFallthroughCasesInSwitch\": true,\n    \"noUnusedLocals\": true,\n    \"noUnusedParameters\": true,\n    \"noEmit\": true,\n    \"isolatedModules\": true,\n    \"skipLibCheck\": true\n  },\n  \"references\": [{ \"path\": \"./tsconfig.node.json\" }],\n  \"include\": [\"src/**/*.ts\", \"src/**/*.d.ts\", \"src/**/*.tsx\", \"src/**/*.vue\"],\n  \"exclude\": [\"dist\", \"node_modules\", \"src/**/*.cy.ts\", \"src/**/*.test.ts\"]\n}\n"
  },
  {
    "path": "tsconfig.node.json",
    "content": "{\n  \"compilerOptions\": {\n    \"composite\": true,\n    \"baseUrl\": \".\",\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"Node\",\n    \"allowSyntheticDefaultImports\": true\n  },\n  \"include\": [\"vite.config.ts\", \"src/**/*.test.ts\"]\n}\n"
  },
  {
    "path": "vite.config.ts",
    "content": "import vue from '@vitejs/plugin-vue'\nimport { defineConfig } from 'vite'\n\nimport banner from 'vite-plugin-banner'\nimport dts from 'vite-plugin-dts'\n/* import analyze from 'rollup-plugin-analyzer' */\n\n/* import { visualizer } from 'rollup-plugin-visualizer' */\nimport { templateCompilerOptions } from '@tresjs/core'\n\nimport { bold, gray, lightGreen, yellow } from 'kolorist'\n\nimport { resolve } from 'pathe'\nimport glsl from 'vite-plugin-glsl'\nimport pkg from './package.json'\n\n// eslint-disable-next-line no-console\nconsole.log(`${lightGreen('▲')} ${gray('■')} ${yellow('♥')} ${bold('Tres/cientos')} v${pkg.version}`)\n// https://vitejs.dev/config/\nexport default defineConfig({\n  resolve: {\n    dedupe: ['@tresjs/core'],\n  },\n  plugins: [\n    vue({\n      isProduction: false,\n      ...templateCompilerOptions,\n    }),\n    dts({\n      insertTypesEntry: true,\n      compilerOptions: {\n        skipLibCheck: true, // Make DTS plugin skip lib check too\n      },\n    }),\n    glsl(),\n    banner({\n      content: `/**\\n * name: ${pkg.name}\\n * version: v${\n        pkg.version\n      }\\n * (c) ${new Date().getFullYear()}\\n * description: ${pkg.description}\\n * author: ${pkg.author}\\n */`,\n    }),\n  ],\n  build: {\n    lib: {\n      entry: resolve(__dirname, 'src/index.ts'),\n      name: 'trescientos',\n      fileName: 'trescientos',\n      formats: ['es'],\n    },\n    copyPublicDir: false,\n    watch: {\n      include: [resolve(__dirname, 'src')],\n    },\n    rollupOptions: {\n      plugins: [\n        /*  analyze(), */\n        /* visualizer({\n          gzipSize: true,\n          brotliSize: true,\n          open: true,\n        }), */\n      ],\n      external: ['three', 'vue', '@tresjs/core'],\n      output: {\n        exports: 'named',\n      },\n    },\n  },\n  optimizeDeps: {\n    exclude: ['three', 'vue', '@tresjs/core'],\n  },\n})\n"
  }
]