[
  {
    "path": ".github/FUNDING.yml",
    "content": "# These are supported funding model platforms\n\ngithub: drcmda\nopen_collective: react-three-fiber\n"
  },
  {
    "path": ".github/workflows/main.yml",
    "content": "name: CI\non:\n  - push\n  - pull_request\njobs:\n  test:\n    name: Node.js ${{ matrix.node-version }}\n    runs-on: ubuntu-latest\n    strategy:\n      fail-fast: false\n      matrix:\n        node-version:\n          - 20\n          - 18\n    steps:\n      - uses: actions/checkout@v3\n      - uses: actions/setup-node@v3\n        with:\n          node-version: ${{ matrix.node-version }}\n      - run: corepack enable\n      - run: yarn install --immutable\n      - run: npm test\n"
  },
  {
    "path": ".gitignore",
    "content": "node_modules/\ncoverage/\ndist/\ntypes/\nThumbs.db\nehthumbs.db\nDesktop.ini\n$RECYCLE.BIN/\n.DS_Store\n.vscode\n.docz/\npackage-lock.json\ncoverage/\n.idea\nyarn-error.log\n"
  },
  {
    "path": ".npmignore",
    "content": "example/"
  },
  {
    "path": ".yarnrc.yml",
    "content": "nodeLinker: node-modules\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2020 Paul Henschel\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": "cli.js",
    "content": "#!/usr/bin/env node\n'use strict'\nimport meow from 'meow'\nimport { fileURLToPath } from 'url'\nimport { dirname } from 'path'\nimport gltfjsx from './src/gltfjsx.js'\nimport { readPackageUpSync } from 'read-pkg-up'\n\nconst __filename = fileURLToPath(import.meta.url)\nconst __dirname = dirname(__filename)\n\nconst cli = meow(\n  `\n\tUsage\n\t  $ npx gltfjsx [Model.glb] [options]\n\n\tOptions\n    --output, -o        Output file name/path\n    --types, -t         Add Typescript definitions\n    --keepnames, -k     Keep original names\n    --keepgroups, -K    Keep (empty) groups, disable pruning\n    --bones, -b         Lay out bones declaratively (default: false)\n    --meta, -m          Include metadata (as userData)\n    --shadows, s        Let meshes cast and receive shadows\n    --printwidth, w     Prettier printWidth (default: 120)\n    --precision, -p     Number of fractional digits (default: 3)\n    --draco, -d         Draco binary path\n    --root, -r          Sets directory from which .gltf file is served\n    --instance, -i      Instance re-occuring geometry\n    --instanceall, -I   Instance every geometry (for cheaper re-use)\n    --exportdefault, -E Use default export\n    --transform, -T     Transform the asset for the web (draco, prune, resize)\n      --resolution, -R  Resolution for texture resizing (default: 1024)\n      --keepmeshes, -j  Do not join compatible meshes\n      --keepmaterials, -M Do not palette join materials\n      --format, -f      Texture format (default: \"webp\")\n      --simplify, -S    Mesh simplification (default: false)\n        --ratio         Simplifier ratio (default: 0)\n        --error         Simplifier error threshold (default: 0.0001)\n    --console, -c       Log JSX to console, won't produce a file\n    --debug, -D         Debug output\n`,\n  {\n    importMeta: import.meta,\n    flags: {\n      output: { type: 'string', shortFlag: 'o' },\n      types: { type: 'boolean', shortFlag: 't' },\n      keepnames: { type: 'boolean', shortFlag: 'k' },\n      keepgroups: { type: 'boolean', shortFlag: 'K' },\n      bones: { type: 'boolean', shortFlag: 'b', default: false },\n      shadows: { type: 'boolean', shortFlag: 's' },\n      printwidth: { type: 'number', shortFlag: 'p', default: 1000 },\n      meta: { type: 'boolean', shortFlag: 'm' },\n      precision: { type: 'number', shortFlag: 'p', default: 3 },\n      draco: { type: 'string', shortFlag: 'd' },\n      root: { type: 'string', shortFlag: 'r' },\n      instance: { type: 'boolean', shortFlag: 'i' },\n      instanceall: { type: 'boolean', shortFlag: 'I' },\n      transform: { type: 'boolean', shortFlag: 'T' },\n      resolution: { type: 'number', shortFlag: 'R', default: 1024 },\n      degrade: { type: 'string', shortFlag: 'q', default: '' },\n      degraderesolution: { type: 'number', shortFlag: 'Q', default: 512 },\n      simplify: { type: 'boolean', shortFlag: 'S', default: false },\n      keepmeshes: { type: 'boolean', shortFlag: 'j', default: false },\n      keepmaterials: { type: 'boolean', shortFlag: 'M', default: false },\n      format: { type: 'string', shortFlag: 'f', default: 'webp' },\n      exportdefault: { type: 'boolean', shortFlag: 'E' },\n      ratio: { type: 'number', default: 0.75 },\n      error: { type: 'number', default: 0.001 },\n      console: { type: 'boolean', shortFlag: 'c' },\n      debug: { type: 'boolean', shortFlag: 'D' },\n    },\n  }\n)\n\nconst { packageJson } = readPackageUpSync({ cwd: __dirname, normalize: false })\n\nif (cli.input.length === 0) {\n  console.log(cli.help)\n} else {\n  const config = {\n    ...cli.flags,\n    header: `Auto-generated by: https://github.com/pmndrs/gltfjsx\nCommand: npx gltfjsx@${packageJson.version} ${process.argv.slice(2).join(' ')}`,\n  }\n  const file = cli.input[0]\n  let nameExt = file.match(/[-_\\w\\d\\s]+[.][\\w]+$/i)[0]\n  let name = nameExt.split('.').slice(0, -1).join('.')\n  const output = config.output ?? name.charAt(0).toUpperCase() + name.slice(1) + (config.types ? '.tsx' : '.jsx')\n  const showLog = (log) => {\n    console.info('log:', log)\n  }\n  try {\n    const response = await gltfjsx(file, output, { ...config, showLog, timeout: 0, delay: 1 })\n  } catch (e) {\n    console.error(e)\n  }\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"gltfjsx\",\n  \"version\": \"6.5.2\",\n  \"description\": \"GLTF to JSX converter\",\n  \"scripts\": {\n    \"build\": \"rollup -c\",\n    \"test\": \"node src/test\"\n  },\n  \"type\": \"module\",\n  \"keywords\": [\n    \"gltf\",\n    \"jsx\",\n    \"react\",\n    \"fiber\",\n    \"three\",\n    \"threejs\",\n    \"webp\"\n  ],\n  \"author\": \"Paul Henschel\",\n  \"maintainers\": [\n    \"Max Rusan\"\n  ],\n  \"license\": \"MIT\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/pmndrs/gltfjsx.git\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/pmndrs/gltfjsx/issues\"\n  },\n  \"homepage\": \"https://github.com/pmndrs/gltfjsx#readme\",\n  \"bin\": \"./cli.js\",\n  \"main\": \"dist/index.cjs\",\n  \"module\": \"dist/index.js\",\n  \"engines\": {\n    \"node\": \">=16\"\n  },\n  \"dependencies\": {\n    \"@gltf-transform/core\": \"4.1.0\",\n    \"@gltf-transform/extensions\": \"4.1.0\",\n    \"@gltf-transform/functions\": \"4.1.0\",\n    \"@node-loader/babel\": \"^2.0.1\",\n    \"draco3dgltf\": \"^1.5.7\",\n    \"is-var-name\": \"^2.0.0\",\n    \"keyframe-resample\": \"^0.1.0\",\n    \"meow\": \"^12.1.1\",\n    \"meshoptimizer\": \"^0.22.0\",\n    \"prettier\": \"3.1.1\",\n    \"read-pkg-up\": \"^10.1.0\",\n    \"three\": \"0.159.0\",\n    \"three-stdlib\": \"^2.28.7\"\n  },\n  \"optionalDependencies\": {\n    \"jsdom\": \"^24.1.0\",\n    \"jsdom-global\": \"^3.0.2\",\n    \"libvips\": \"0.0.2\",\n    \"sharp\": \"^0.33.5\"\n  },\n  \"resolutions\": {\n    \"sharp\": \"<0.33.0\",\n    \"@gltf-transform/core\": \"4.0.8\",\n    \"@gltf-transform/extensions\": \"4.0.8\",\n    \"@gltf-transform/functions\": \"4.0.8\"\n  },\n  \"devDependencies\": {\n    \"@babel/core\": \"7.23.6\",\n    \"@babel/plugin-proposal-class-properties\": \"^7.16.0\",\n    \"@babel/plugin-transform-modules-commonjs\": \"7.23.3\",\n    \"@babel/plugin-transform-parameters\": \"7.23.3\",\n    \"@babel/plugin-transform-runtime\": \"7.23.6\",\n    \"@babel/plugin-transform-template-literals\": \"7.23.3\",\n    \"@babel/preset-env\": \"7.23.6\",\n    \"@babel/preset-react\": \"7.23.3\",\n    \"@babel/preset-typescript\": \"^7.23.3\",\n    \"@rollup/plugin-babel\": \"^6.0.4\",\n    \"@rollup/plugin-node-resolve\": \"^15.2.3\",\n    \"chalk\": \"^5.3.0\",\n    \"fast-glob\": \"^3.3.2\",\n    \"fs-extra\": \"^11.2.0\",\n    \"lint-staged\": \"^13.2.0\",\n    \"rollup\": \"^4.9.1\",\n    \"rollup-plugin-size-snapshot\": \"^0.12.0\",\n    \"rollup-plugin-terser\": \"^7.0.2\"\n  },\n  \"prettier\": {\n    \"semi\": false,\n    \"trailingComma\": \"es5\",\n    \"singleQuote\": true,\n    \"jsxBracketSameLine\": true,\n    \"tabWidth\": 2,\n    \"printWidth\": 120\n  },\n  \"lint-staged\": {\n    \"*.{js,jsx,ts,tsx}\": [\n      \"prettier --write\"\n    ]\n  },\n  \"collective\": {\n    \"type\": \"opencollective\",\n    \"url\": \"https://opencollective.com/react-three-fiber\"\n  },\n  \"packageManager\": \"yarn@4.4.0+sha256.5f228cb28f2edb97d8c3b667fb7b2fdcf06c46798e25ea889dad9e0b4bc2e2c1\"\n}\n"
  },
  {
    "path": "readme.md",
    "content": "https://user-images.githubusercontent.com/2223602/126318148-99da7ed6-a578-48dd-bdd2-21056dbad003.mp4\n\n<br />\n<br/>\n\n[![Version](https://img.shields.io/npm/v/gltfjsx?style=flat&colorA=000000&colorB=000000)](https://www.npmjs.com/package/gltfjsx) [![Discord Shield](https://img.shields.io/discord/740090768164651008?style=flat&colorA=000000&colorB=000000&label=discord&logo=discord&logoColor=ffffff)](https://discord.gg/ZZjjNvJ)\n\nA small command-line tool that turns GLTF assets into declarative and re-usable [react-three-fiber](https://github.com/pmndrs/react-three-fiber) JSX components.\n\n### The GLTF workflow on the web is not ideal ...\n\n- GLTF is thrown whole into the scene which prevents re-use, in threejs objects can only be mounted once\n- Contents can only be found by traversal which is cumbersome and slow\n- Changes to queried nodes are made by mutation, which alters the source data and prevents re-use\n- Re-structuring content, making nodes conditional or adding/removing is cumbersome\n- Model compression is complex and not easily achieved\n- Models often have unnecessary nodes that cause extra work and matrix updates\n\n### GLTFJSX fixes that\n\n- 🧑‍💻 It creates a virtual graph of all objects and materials. Now you can easily alter contents and re-use.\n- 🏎️ The graph gets pruned (empty groups, unnecessary transforms, ...) and will perform better.\n- ⚡️ It will optionally compress your model with up to 70%-90% size reduction.\n\n## Usage\n\n```text\nUsage\n  $ npx gltfjsx [Model.glb] [options]\n\nOptions\n  --output, -o        Output file name/path\n  --types, -t         Add Typescript definitions\n  --keepnames, -k     Keep original names\n  --keepgroups, -K    Keep (empty) groups, disable pruning\n  --bones, -b         Lay out bones declaratively (default: false)\n  --meta, -m          Include metadata (as userData)\n  --shadows, s        Let meshes cast and receive shadows\n  --printwidth, w     Prettier printWidth (default: 120)\n  --precision, -p     Number of fractional digits (default: 3)\n  --draco, -d         Draco binary path\n  --root, -r          Sets directory from which .gltf file is served\n  --instance, -i      Instance re-occuring geometry\n  --instanceall, -I   Instance every geometry (for cheaper re-use)\n  --exportdefault, -E Use default export\n  --transform, -T     Transform the asset for the web (draco, prune, resize)\n    --resolution, -R  Resolution for texture resizing (default: 1024)\n    --keepmeshes, -j  Do not join compatible meshes\n    --keepmaterials, -M Do not palette join materials\n    --format, -f      Texture format (default: \"webp\")\n    --simplify, -S    Mesh simplification (default: false)\n      --ratio         Simplifier ratio (default: 0)\n      --error         Simplifier error threshold (default: 0.0001)\n  --console, -c       Log JSX to console, won't produce a file\n  --debug, -D         Debug output\n```\n\n### A typical use-case\n\nFirst you run your model through gltfjsx. `npx` allows you to use npm packages without installing them.\n\n```bash\nnpx gltfjsx model.gltf --transform\n```\n\nThis will create a `Model.jsx` file that plots out all of the assets contents.\n\n```jsx\n/*\nauto-generated by: https://github.com/pmdrs/gltfjsx\nauthor: abcdef (https://sketchfab.com/abcdef)\nlicense: CC-BY-4.0 (http://creativecommons.org/licenses/by/4.0/)\nsource: https://sketchfab.com/models/...\ntitle: Model\n*/\n\nimport { useGLTF, PerspectiveCamera } from '@react-three/drei'\n\nexport function Model(props) {\n  const { nodes, materials } = useGLTF('/model-transformed.glb')\n  return (\n    <group {...props} dispose={null}>\n      <PerspectiveCamera name=\"camera\" fov={40} near={10} far={1000} position={[10, 0, 50]} />\n      <pointLight intensity={10} position={[100, 50, 100]} rotation={[-Math.PI / 2, 0, 0]} />\n      <group position={[10, -5, 0]}>\n        <mesh geometry={nodes.robot.geometry} material={materials.metal} />\n        <mesh geometry={nodes.rocket.geometry} material={materials.wood} />\n      </group>\n    </group>\n  )\n}\n\nuseGLTF.preload('/model.gltf')\n```\n\nAdd your model to your `/public` folder as you would normally do. With the `--transform` flag it has created a compressed copy of it (in the above case `model-transformed.glb`). Without the flag just copy the original model.\n\n```text\n/public\n  model-transformed.glb\n```\n\nThe component can now be dropped into your scene.\n\n```jsx\nimport { Canvas } from '@react-three/fiber'\nimport { Model } from './Model'\n\nfunction App() {\n  return (\n    <Canvas>\n      <Model />\n```\n\nYou can re-use it, it will re-use geometries and materials out of the box:\n\n```jsx\n<Model position={[0, 0, 0]} />\n<Model position={[10, 0, -10]} />\n```\n\nOr make the model dynamic. Change its colors for example:\n\n```jsx\n<mesh geometry={nodes.robot.geometry} material={materials.metal} material-color=\"green\" />\n```\n\nOr exchange materials:\n\n```jsx\n<mesh geometry={nodes.robot.geometry}>\n  <meshPhysicalMaterial color=\"hotpink\" />\n</mesh>\n```\n\nMake contents conditional:\n\n```jsx\n{condition && <mesh geometry={nodes.robot.geometry} material={materials.metal} />}\n```\n\nAdd events:\n\n```jsx\n<mesh geometry={nodes.robot.geometry} material={materials.metal} onClick={handleClick} />\n```\n\n## Features\n\n#### ⚡️ Draco and meshopt compression ootb\n\nYou don't need to do anything if your models are draco compressed, since `useGLTF` defaults to a [draco CDN](https://www.gstatic.com/draco/v1/decoders/). By adding the `--draco` flag you can refer to [local binaries](https://github.com/mrdoob/three.js/tree/dev/examples/js/libs/draco/gltf) which must reside in your /public folder.\n\n#### ⚡️ Preload your assets for faster response\n\nThe asset will be preloaded by default, this makes it quicker to load and reduces time-to-paint. Remove the preloader if you don't need it.\n\n```jsx\nuseGLTF.preload('/model.gltf')\n```\n\n#### ⚡️ Auto-transform (compression, resize)\n\nWith the `--transform` flag it creates a binary-packed, draco-compressed, texture-resized (1024x1024), webp compressed, deduped, instanced and pruned *.glb ready to be consumed on a web site. It uses [glTF-Transform](https://github.com/donmccurdy/glTF-Transform). This can reduce the size of an asset by 70%-90%.\n\nIt will not alter the original but create a copy and append `[modelname]-transformed.glb`.\n\n#### ⚡️ Type-safety\n\nAdd the `--types` flag and your GLTF will be typesafe.\n\n```tsx\ntype GLTFResult = GLTF & {\n  nodes: { robot: THREE.Mesh; rocket: THREE.Mesh }\n  materials: { metal: THREE.MeshStandardMaterial; wood: THREE.MeshStandardMaterial }\n}\n\nexport default function Model(props: JSX.IntrinsicElements['group']) {\n  const { nodes, materials } = useGLTF<GLTFResult>('/model.gltf')\n```\n\n#### ⚡️ Easier access to animations\n\nIf your GLTF contains animations it will add [drei's](https://github.com/pmndrs/drei) `useAnimations` hook, which extracts all clips and prepares them as actions:\n\n```jsx\nconst { nodes, materials, animations } = useGLTF('/model.gltf')\nconst { actions } = useAnimations(animations, group)\n```\n\nIf you want to play an animation you can do so at any time:\n\n```jsx\n<mesh onClick={(e) => actions.jump.play()} />\n```\n\nIf you want to blend animations:\n\n```jsx\nconst [name, setName] = useState(\"jump\")\n...\nuseEffect(() => {\n  actions[name].reset().fadeIn(0.5).play()\n  return () => actions[name].fadeOut(0.5)\n}, [name])\n```\n\n#### ⚡️ Auto-instancing\n\nUse the `--instance` flag and it will look for similar geometry and create instances of them. Look into [drei/Merged](https://github.com/pmndrs/drei#instances) to understand how it works. It does not matter if you instanced the model previously in Blender, it creates instances for each mesh that has a specific geometry and/or material.\n\n`--instanceall` will create instances of all the geometry. This allows you to re-use the model with the smallest amount of drawcalls.\n\nYour export will look like something like this:\n\n```jsx\nconst context = createContext()\nexport function Instances({ children, ...props }) {\n  const { nodes } = useGLTF('/model-transformed.glb')\n  const instances = useMemo(() => ({ Screw1: nodes['Screw1'], Screw2: nodes['Screw2'] }), [nodes])\n  return (\n    <Merged meshes={instances} {...props}>\n      {(instances) => <context.Provider value={instances} children={children} />}\n    </Merged>\n  )\n}\n\nexport function Model(props) {\n  const instances = useContext(context)\n  return (\n    <group {...props} dispose={null}>\n      <instances.Screw1 position={[-0.42, 0.04, -0.08]} rotation={[-Math.PI / 2, 0, 0]} />\n      <instances.Screw2 position={[-0.42, 0.04, -0.08]} rotation={[-Math.PI / 2, 0, 0]} />\n    </group>\n  )\n}\n```\n\nNote that similar to `--transform` it also has to transform the model. In order to use and re-use the model import both `Instances` and `Model`. Put all your models into the `Instances` component (you can nest).\n\nThe following will show the model three times, but you will only have 2 drawcalls tops.\n\n```jsx\nimport { Instances, Model } from './Model'\n\n<Instances>\n  <Model position={[10,0,0]}>\n  <Model position={[-10,0,0]}>\n  <Model position={[-10,10,0]}>\n</Instance>\n```\n\n## Using the parser stand-alone\n\n```jsx\nimport { parse } from 'gltfjsx'\nimport { GLTFLoader, DRACOLoader } from 'three-stdlib'\n\nconst gltfLoader = new GLTFLoader()\nconst dracoloader = new DRACOLoader()\ndracoloader.setDecoderPath('https://www.gstatic.com/draco/v1/decoders/')\ngltfLoader.setDRACOLoader(dracoloader)\n\ngltfLoader.load(url, (gltf) => {\n  const jsx = parse(gltf, optionalConfig)\n})\n```\n\n## Using the parser stand-alone for scenes (object3d's)\n\n```jsx\nconst jsx = parse(scene, optionalConfig)\n```\n\n## Using GLTFStructureLoader stand-alone\n\nThe GLTFStructureLoader can come in handy while testing gltf assets. It allows you to extract the structure without the actual binaries and textures making it possible to run in a testing environment.\n\n```jsx\nimport { GLTFStructureLoader } from 'gltfjsx'\nimport fs from 'fs/promises'\n\nit('should have a scene with a blue mesh', async () => {\n  const loader = new GLTFStructureLoader()\n  const data = await fs.readFile('./model.glb')\n  const { scene } = await new Promise((res) => loader.parse(data, '', res))\n  expect(() => scene.children.length).toEqual(1)\n  expect(() => scene.children[0].type).toEqual('mesh')\n  expect(() => scene.children[0].material.color).toEqual('blue')\n})\n```\n\n## Requirements\n\n- Nodejs must be installed\n- The GLTF file has to be present in your projects `/public` folder\n- [three](https://github.com/mrdoob/three.js/) (>= 122.x)\n- [@react-three/fiber](https://github.com/pmndrs/react-three-fiber) (>= 5.x)\n- [@react-three/drei](https://github.com/pmndrs/drei) (>= 2.x)\n"
  },
  {
    "path": "rollup.config.js",
    "content": "import path from 'path'\nimport babel from '@rollup/plugin-babel'\nimport resolve from '@rollup/plugin-node-resolve'\n\nconst root = process.platform === 'win32' ? path.resolve('/') : '/'\nconst external = (id) => !id.startsWith('.') && !id.startsWith(root)\nconst extensions = ['.js', '.jsx', '.ts', '.tsx', '.json']\n\nconst getBabelOptions = ({ useESModules }) => ({\n  babelrc: false,\n  extensions,\n  exclude: '**/node_modules/**',\n  babelHelpers: 'runtime',\n  presets: [\n    [\n      '@babel/preset-env',\n      {\n        include: [\n          '@babel/plugin-proposal-optional-chaining',\n          '@babel/plugin-proposal-nullish-coalescing-operator',\n          '@babel/plugin-proposal-numeric-separator',\n          '@babel/plugin-proposal-logical-assignment-operators',\n        ],\n        bugfixes: true,\n        loose: true,\n        modules: false,\n        targets: '> 1%, not dead, not ie 11, not op_mini all',\n      },\n    ],\n  ],\n  plugins: [['@babel/transform-runtime', { regenerator: false, useESModules }]],\n})\n\nexport default [\n  {\n    input: `./src/utils/exports.js`,\n    output: { file: `dist/index.js`, format: 'esm' },\n    external,\n    plugins: [babel(getBabelOptions({ useESModules: true })), resolve({ extensions })],\n  },\n  {\n    input: `./src/utils/exports.js`,\n    output: { file: `dist/index.cjs.js`, format: 'cjs' },\n    external,\n    plugins: [babel(getBabelOptions({ useESModules: false })), resolve({ extensions })],\n  },\n]\n"
  },
  {
    "path": "src/bin/DRACOLoader.js",
    "content": "import * as THREE from 'three'\nimport draco from 'draco3dgltf'\n\nconst decoder = draco.createDecoderModule()\nconst DRACOLoader = function (t) {\n  ;(this.timeLoaded = 0),\n    (this.manager = t || THREE.DefaultLoadingManager),\n    (this.materials = null),\n    (this.verbosity = 0),\n    (this.attributeOptions = {}),\n    (this.drawMode = THREE.TrianglesDrawMode),\n    (this.nativeAttributeMap = { position: 'POSITION', normal: 'NORMAL', color: 'COLOR', uv: 'TEX_COORD' })\n}\n\nDRACOLoader.prototype = {\n  constructor: DRACOLoader,\n  load: function (t, e, r, o) {\n    var i = this,\n      n = new THREE.FileLoader(i.manager)\n    n.setPath(this.path),\n      n.setResponseType('arraybuffer'),\n      n.load(\n        t,\n        function (t) {\n          i.decodeDracoFile(t, e)\n        },\n        r,\n        o\n      )\n  },\n  setPath: function (t) {\n    return (this.path = t), this\n  },\n  setVerbosity: function (t) {\n    return (this.verbosity = t), this\n  },\n  setDrawMode: function (t) {\n    return (this.drawMode = t), this\n  },\n  setSkipDequantization: function (t, e) {\n    var r = !0\n    return void 0 !== e && (r = e), (this.getAttributeOptions(t).skipDequantization = r), this\n  },\n  decodeDracoFile: function (t, e, r, o) {\n    decoder.then((decoder) => this.decodeDracoFileInternal(t, decoder, e, r, o))\n  },\n  decodeDracoFileInternal: function (t, e, r, o, i) {\n    var n = new e.DecoderBuffer()\n    n.Init(new Int8Array(t), t.byteLength)\n    var a = new e.Decoder(),\n      s = a.GetEncodedGeometryType(n)\n    if (s == e.TRIANGULAR_MESH) this.verbosity > 0 && console.log('Loaded a mesh.')\n    else {\n      if (s != e.POINT_CLOUD) {\n        var u = 'THREE.DRACOLoader: Unknown geometry type.'\n        //throw (console.error(u), new Error(u))\n      }\n      this.verbosity > 0 && console.log('Loaded a point cloud.')\n    }\n    r(this.convertDracoGeometryTo3JS(e, a, s, n, o, i))\n  },\n  addAttributeToGeometry: function (t, e, r, o, i, n, a, s) {\n    if (0 === n.ptr) {\n      var u = 'THREE.DRACOLoader: No attribute ' + o\n      throw (console.error(u), new Error(u))\n    }\n    var d,\n      A,\n      c = n.num_components(),\n      l = r.num_points() * c\n    switch (i) {\n      case Float32Array:\n        ;(d = new t.DracoFloat32Array()),\n          e.GetAttributeFloatForAllPoints(r, n, d),\n          (s[o] = new Float32Array(l)),\n          (A = THREE.Float32BufferAttribute)\n        break\n      case Int8Array:\n        ;(d = new t.DracoInt8Array()),\n          e.GetAttributeInt8ForAllPoints(r, n, d),\n          (s[o] = new Int8Array(l)),\n          (A = THREE.Int8BufferAttribute)\n        break\n      case Int16Array:\n        ;(d = new t.DracoInt16Array()),\n          e.GetAttributeInt16ForAllPoints(r, n, d),\n          (s[o] = new Int16Array(l)),\n          (A = THREE.Int16BufferAttribute)\n        break\n      case Int32Array:\n        ;(d = new t.DracoInt32Array()),\n          e.GetAttributeInt32ForAllPoints(r, n, d),\n          (s[o] = new Int32Array(l)),\n          (A = THREE.Int32BufferAttribute)\n        break\n      case Uint8Array:\n        ;(d = new t.DracoUInt8Array()),\n          e.GetAttributeUInt8ForAllPoints(r, n, d),\n          (s[o] = new Uint8Array(l)),\n          (A = THREE.Uint8BufferAttribute)\n        break\n      case Uint16Array:\n        ;(d = new t.DracoUInt16Array()),\n          e.GetAttributeUInt16ForAllPoints(r, n, d),\n          (s[o] = new Uint16Array(l)),\n          (A = THREE.Uint16BufferAttribute)\n        break\n      case Uint32Array:\n        ;(d = new t.DracoUInt32Array()),\n          e.GetAttributeUInt32ForAllPoints(r, n, d),\n          (s[o] = new Uint32Array(l)),\n          (A = THREE.Uint32BufferAttribute)\n        break\n      default:\n        u = 'THREE.DRACOLoader: Unexpected attribute type.'\n        throw (console.error(u), new Error(u))\n    }\n    for (var b = 0; b < l; b++) s[o][b] = d.GetValue(b)\n    a.setAttribute(o, new A(s[o], c)), t.destroy(d)\n  },\n  convertDracoGeometryTo3JS: function (t, e, r, o, i, n) {\n    var a, s, u\n    if (\n      (!0 === this.getAttributeOptions('position').skipDequantization && e.SkipAttributeTransform(t.POSITION),\n      r === t.TRIANGULAR_MESH\n        ? ((a = new t.Mesh()), (s = e.DecodeBufferToMesh(o, a)))\n        : ((a = new t.PointCloud()), (s = e.DecodeBufferToPointCloud(o, a))),\n      !s.ok() || 0 == a.ptr)\n    ) {\n      return new THREE.BufferGeometry()\n      var d = 'THREE.DRACOLoader: Decoding failed: '\n      throw ((d += s.error_msg()), console.error(d), t.destroy(e), t.destroy(a), new Error(d))\n    }\n    t.destroy(o),\n      r == t.TRIANGULAR_MESH\n        ? ((u = a.num_faces()), this.verbosity > 0 && console.log('Number of faces loaded: ' + u.toString()))\n        : (u = 0)\n    var A = a.num_points(),\n      c = a.num_attributes()\n    this.verbosity > 0 &&\n      (console.log('Number of points loaded: ' + A.toString()),\n      console.log('Number of attributes loaded: ' + c.toString()))\n    var l = e.GetAttributeId(a, t.POSITION)\n    if (-1 == l) {\n      d = 'THREE.DRACOLoader: No position attribute found.'\n      throw (console.error(d), t.destroy(e), t.destroy(a), new Error(d))\n    }\n    var b = e.GetAttribute(a, l),\n      f = {},\n      y = new THREE.BufferGeometry()\n    if (i)\n      for (var E in i) {\n        var h = n[E],\n          w = i[E],\n          p = e.GetAttributeByUniqueId(a, w)\n        //this.addAttributeToGeometry(t, e, a, E, h, p, y, f)\n      }\n    else\n      for (var E in this.nativeAttributeMap) {\n        var T = e.GetAttributeId(a, t[this.nativeAttributeMap[E]])\n        if (-1 !== T) {\n          this.verbosity > 0 && console.log('Loaded ' + E + ' attribute.')\n          p = e.GetAttribute(a, T)\n          //this.addAttributeToGeometry(t, e, a, E, Float32Array, p, y, f)\n        }\n      }\n    if (r == t.TRIANGULAR_MESH)\n      if (this.drawMode === THREE.TriangleStripDrawMode) {\n        var R = new t.DracoInt32Array()\n        e.GetTriangleStripsFromMesh(a, R)\n        f.indices = new Uint32Array(R.size())\n        for (var I = 0; I < R.size(); ++I) f.indices[I] = R.GetValue(I)\n        t.destroy(R)\n      } else {\n        var v = 3 * u\n        f.indices = new Uint32Array(v)\n        var D = new t.DracoInt32Array()\n        for (I = 0; I < u; ++I) {\n          e.GetFaceFromMesh(a, I, D)\n          var m = 3 * I\n          ;(f.indices[m] = D.GetValue(0)), (f.indices[m + 1] = D.GetValue(1)), (f.indices[m + 2] = D.GetValue(2))\n        }\n        t.destroy(D)\n      }\n    ;(y.drawMode = this.drawMode),\n      r == t.TRIANGULAR_MESH &&\n        y.setIndex(\n          new (f.indices.length > 65535 ? THREE.Uint32BufferAttribute : THREE.Uint16BufferAttribute)(f.indices, 1)\n        )\n    var G = new t.AttributeQuantizationTransform()\n    if (G.InitFromAttribute(b)) {\n      ;(y.attributes.position.isQuantized = !0),\n        (y.attributes.position.maxRange = G.range()),\n        (y.attributes.position.numQuantizationBits = G.quantization_bits()),\n        (y.attributes.position.minValues = new Float32Array(3))\n      for (I = 0; I < 3; ++I) y.attributes.position.minValues[I] = G.min_value(I)\n    }\n    return t.destroy(G), t.destroy(e), t.destroy(a), y\n  },\n  isVersionSupported: function (t, e) {\n    e(decoder.isVersionSupported(t))\n  },\n  getAttributeOptions: function (t) {\n    return void 0 === this.attributeOptions[t] && (this.attributeOptions[t] = {}), this.attributeOptions[t]\n  },\n}\n\nexport { DRACOLoader }\n"
  },
  {
    "path": "src/bin/GLTFLoader.js",
    "content": "import * as THREE from 'three'\n\nexport class GLTFLoader extends THREE.Loader {\n  constructor() {\n    super()\n    this.dracoLoader = null\n    this.ddsLoader = null\n    this.ktx2Loader = null\n\n    this.pluginCallbacks = []\n\n    this.register(function (parser) {\n      return new GLTFMaterialsClearcoatExtension(parser)\n    })\n\n    this.register(function (parser) {\n      return new GLTFTextureBasisUExtension(parser)\n    })\n\n    this.register(function (parser) {\n      return new GLTFMaterialsTransmissionExtension(parser)\n    })\n\n    this.register(function (parser) {\n      return new GLTFLightsExtension(parser)\n    })\n    this.register(function (parser) {\n      return new GLTFMeshGpuInstancing(parser)\n    })\n  }\n\n  load(url, onLoad, onProgress, onError) {\n    var scope = this\n\n    var resourcePath\n\n    if (this.resourcePath !== '') {\n      resourcePath = this.resourcePath\n    } else if (this.path !== '') {\n      resourcePath = this.path\n    } else {\n      resourcePath = THREE.LoaderUtils.extractUrlBase(url)\n    }\n\n    // Tells the LoadingManager to track an extra item, which resolves after\n    // the model is fully loaded. This means the count of items loaded will\n    // be incorrect, but ensures manager.onLoad() does not fire early.\n    this.manager.itemStart(url)\n\n    var _onError = function (e) {\n      if (onError) {\n        onError(e)\n      } else {\n        console.error(e)\n      }\n\n      scope.manager.itemError(url)\n      scope.manager.itemEnd(url)\n    }\n\n    var loader = new THREE.FileLoader(this.manager)\n\n    loader.setPath(this.path)\n    loader.setResponseType('arraybuffer')\n    loader.setRequestHeader(this.requestHeader)\n    loader.setWithCredentials(this.withCredentials)\n\n    loader.load(\n      url,\n      function (data) {\n        try {\n          scope.parse(\n            data,\n            resourcePath,\n            function (gltf) {\n              onLoad(gltf)\n\n              scope.manager.itemEnd(url)\n            },\n            _onError\n          )\n        } catch (e) {\n          _onError(e)\n        }\n      },\n      onProgress,\n      _onError\n    )\n  }\n\n  setDRACOLoader(dracoLoader) {\n    this.dracoLoader = dracoLoader\n    return this\n  }\n\n  setDDSLoader(ddsLoader) {\n    this.ddsLoader = ddsLoader\n    return this\n  }\n\n  setKTX2Loader(ktx2Loader) {\n    this.ktx2Loader = ktx2Loader\n    return this\n  }\n\n  register(callback) {\n    if (this.pluginCallbacks.indexOf(callback) === -1) {\n      this.pluginCallbacks.push(callback)\n    }\n\n    return this\n  }\n\n  unregister(callback) {\n    if (this.pluginCallbacks.indexOf(callback) !== -1) {\n      this.pluginCallbacks.splice(this.pluginCallbacks.indexOf(callback), 1)\n    }\n\n    return this\n  }\n\n  parse(data, path, onLoad, onError) {\n    var content\n    var extensions = {}\n    var plugins = {}\n\n    if (typeof data === 'string') {\n      content = data\n    } else {\n      var magic = THREE.LoaderUtils.decodeText(new Uint8Array(data, 0, 4))\n\n      if (magic === BINARY_EXTENSION_HEADER_MAGIC) {\n        try {\n          extensions[EXTENSIONS.KHR_BINARY_GLTF] = new GLTFBinaryExtension(data)\n        } catch (error) {\n          if (onError) onError(error)\n          return\n        }\n\n        content = extensions[EXTENSIONS.KHR_BINARY_GLTF].content\n      } else {\n        content = THREE.LoaderUtils.decodeText(new Uint8Array(data))\n      }\n    }\n\n    var json = JSON.parse(content)\n\n    if (json.asset === undefined || json.asset.version[0] < 2) {\n      if (onError) onError(new Error('THREE.GLTFLoader: Unsupported asset. glTF versions >=2.0 are supported.'))\n      return\n    }\n\n    var parser = new GLTFParser(json, {\n      path: path || this.resourcePath || '',\n      crossOrigin: this.crossOrigin,\n      manager: this.manager,\n      ktx2Loader: this.ktx2Loader,\n    })\n\n    parser.fileLoader.setRequestHeader(this.requestHeader)\n\n    for (var i = 0; i < this.pluginCallbacks.length; i++) {\n      var plugin = this.pluginCallbacks[i](parser)\n      plugins[plugin.name] = plugin\n\n      // Workaround to avoid determining as unknown extension\n      // in addUnknownExtensionsToUserData().\n      // Remove this workaround if we move all the existing\n      // extension handlers to plugin system\n      extensions[plugin.name] = true\n    }\n\n    if (json.extensionsUsed) {\n      for (var i = 0; i < json.extensionsUsed.length; ++i) {\n        var extensionName = json.extensionsUsed[i]\n        var extensionsRequired = json.extensionsRequired || []\n\n        switch (extensionName) {\n          case EXTENSIONS.KHR_MATERIALS_UNLIT:\n            extensions[extensionName] = new GLTFMaterialsUnlitExtension()\n            break\n\n          case EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS:\n            extensions[extensionName] = new GLTFMaterialsPbrSpecularGlossinessExtension()\n            break\n\n          case EXTENSIONS.KHR_DRACO_MESH_COMPRESSION:\n            extensions[extensionName] = new GLTFDracoMeshCompressionExtension(json, this.dracoLoader)\n            break\n\n          case EXTENSIONS.MSFT_TEXTURE_DDS:\n            extensions[extensionName] = new GLTFTextureDDSExtension(this.ddsLoader)\n            break\n\n          case EXTENSIONS.KHR_TEXTURE_TRANSFORM:\n            extensions[extensionName] = new GLTFTextureTransformExtension()\n            break\n\n          case EXTENSIONS.KHR_MESH_QUANTIZATION:\n            extensions[extensionName] = new GLTFMeshQuantizationExtension()\n            break\n\n          default:\n            if (extensionsRequired.indexOf(extensionName) >= 0 && plugins[extensionName] === undefined) {\n              // console.warn('THREE.GLTFLoader: Unknown extension \"' + extensionName + '\".')\n            }\n        }\n      }\n    }\n\n    parser.setExtensions(extensions)\n    parser.setPlugins(plugins)\n    parser.parse(onLoad, onError)\n  }\n}\n\n/* GLTFREGISTRY */\n\nfunction GLTFRegistry() {\n  var objects = {}\n\n  return {\n    get: function (key) {\n      return objects[key]\n    },\n\n    add: function (key, object) {\n      objects[key] = object\n    },\n\n    remove: function (key) {\n      delete objects[key]\n    },\n\n    removeAll: function () {\n      objects = {}\n    },\n  }\n}\n\n/*********************************/\n/********** EXTENSIONS ***********/\n/*********************************/\n\nvar EXTENSIONS = {\n  KHR_BINARY_GLTF: 'KHR_binary_glTF',\n  KHR_DRACO_MESH_COMPRESSION: 'KHR_draco_mesh_compression',\n  KHR_LIGHTS_PUNCTUAL: 'KHR_lights_punctual',\n  KHR_MATERIALS_CLEARCOAT: 'KHR_materials_clearcoat',\n  KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS: 'KHR_materials_pbrSpecularGlossiness',\n  KHR_MATERIALS_TRANSMISSION: 'KHR_materials_transmission',\n  KHR_MATERIALS_UNLIT: 'KHR_materials_unlit',\n  KHR_TEXTURE_BASISU: 'KHR_texture_basisu',\n  KHR_TEXTURE_TRANSFORM: 'KHR_texture_transform',\n  KHR_MESH_QUANTIZATION: 'KHR_mesh_quantization',\n  MSFT_TEXTURE_DDS: 'MSFT_texture_dds',\n  EXT_MESH_GPU_INSTANCING: 'EXT_mesh_gpu_instancing',\n}\n\n/**\n * DDS Texture Extension\n *\n * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/MSFT_texture_dds\n *\n */\nfunction GLTFTextureDDSExtension(ddsLoader) {\n  if (!ddsLoader) {\n    throw new Error('THREE.GLTFLoader: Attempting to load .dds texture without importing THREE.DDSLoader')\n  }\n\n  this.name = EXTENSIONS.MSFT_TEXTURE_DDS\n  this.ddsLoader = ddsLoader\n}\n\n/**\n * Punctual Lights Extension\n *\n * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_lights_punctual\n */\nfunction GLTFLightsExtension(parser) {\n  this.parser = parser\n  this.name = EXTENSIONS.KHR_LIGHTS_PUNCTUAL\n\n  // Object3D instance caches\n  this.cache = { refs: {}, uses: {} }\n}\n\nGLTFLightsExtension.prototype._markDefs = function () {\n  var parser = this.parser\n  var nodeDefs = this.parser.json.nodes || []\n\n  for (var nodeIndex = 0, nodeLength = nodeDefs.length; nodeIndex < nodeLength; nodeIndex++) {\n    var nodeDef = nodeDefs[nodeIndex]\n\n    if (nodeDef.extensions && nodeDef.extensions[this.name] && nodeDef.extensions[this.name].light !== undefined) {\n      parser._addNodeRef(this.cache, nodeDef.extensions[this.name].light)\n    }\n  }\n}\n\nGLTFLightsExtension.prototype._loadLight = function (lightIndex) {\n  var parser = this.parser\n  var cacheKey = 'light:' + lightIndex\n  var dependency = parser.cache.get(cacheKey)\n\n  if (dependency) return dependency\n\n  var json = parser.json\n  var extensions = (json.extensions && json.extensions[this.name]) || {}\n  var lightDefs = extensions.lights || []\n  var lightDef = lightDefs[lightIndex]\n  var lightNode\n\n  var color = new THREE.Color(0xffffff)\n\n  if (lightDef.color !== undefined) color.fromArray(lightDef.color)\n\n  var range = lightDef.range !== undefined ? lightDef.range : 0\n\n  switch (lightDef.type) {\n    case 'directional':\n      lightNode = new THREE.DirectionalLight(color)\n      lightNode.target.position.set(0, 0, -1)\n      lightNode.add(lightNode.target)\n      break\n\n    case 'point':\n      lightNode = new THREE.PointLight(color)\n      lightNode.distance = range\n      break\n\n    case 'spot':\n      lightNode = new THREE.SpotLight(color)\n      lightNode.distance = range\n      // Handle spotlight properties.\n      lightDef.spot = lightDef.spot || {}\n      lightDef.spot.innerConeAngle = lightDef.spot.innerConeAngle !== undefined ? lightDef.spot.innerConeAngle : 0\n      lightDef.spot.outerConeAngle =\n        lightDef.spot.outerConeAngle !== undefined ? lightDef.spot.outerConeAngle : Math.PI / 4.0\n      lightNode.angle = lightDef.spot.outerConeAngle\n      lightNode.penumbra = 1.0 - lightDef.spot.innerConeAngle / lightDef.spot.outerConeAngle\n      lightNode.target.position.set(0, 0, -1)\n      lightNode.add(lightNode.target)\n      break\n\n    default:\n      throw new Error('THREE.GLTFLoader: Unexpected light type, \"' + lightDef.type + '\".')\n  }\n\n  // Some lights (e.g. spot) default to a position other than the origin. Reset the position\n  // here, because node-level parsing will only override position if explicitly specified.\n  lightNode.position.set(0, 0, 0)\n\n  lightNode.decay = 2\n\n  if (lightDef.intensity !== undefined) lightNode.intensity = lightDef.intensity\n\n  lightNode.name = parser.createUniqueName(lightDef.name || 'light_' + lightIndex)\n\n  dependency = Promise.resolve(lightNode)\n\n  parser.cache.add(cacheKey, dependency)\n\n  return dependency\n}\n\nGLTFLightsExtension.prototype.createNodeAttachment = function (nodeIndex) {\n  var self = this\n  var parser = this.parser\n  var json = parser.json\n  var nodeDef = json.nodes[nodeIndex]\n  var lightDef = (nodeDef.extensions && nodeDef.extensions[this.name]) || {}\n  var lightIndex = lightDef.light\n\n  if (lightIndex === undefined) return null\n\n  return this._loadLight(lightIndex).then(function (light) {\n    return parser._getNodeRef(self.cache, lightIndex, light)\n  })\n}\n\n/**\n * Unlit Materials Extension\n *\n * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_unlit\n */\nfunction GLTFMaterialsUnlitExtension() {\n  this.name = EXTENSIONS.KHR_MATERIALS_UNLIT\n}\n\nGLTFMaterialsUnlitExtension.prototype.getMaterialType = function () {\n  return THREE.MeshBasicMaterial\n}\n\nGLTFMaterialsUnlitExtension.prototype.extendParams = function (materialParams, materialDef, parser) {\n  var pending = []\n\n  materialParams.color = new THREE.Color(1.0, 1.0, 1.0)\n  materialParams.opacity = 1.0\n\n  var metallicRoughness = materialDef.pbrMetallicRoughness\n\n  if (metallicRoughness) {\n    if (Array.isArray(metallicRoughness.baseColorFactor)) {\n      var array = metallicRoughness.baseColorFactor\n\n      materialParams.color.fromArray(array)\n      materialParams.opacity = array[3]\n    }\n  }\n\n  return Promise.all(pending)\n}\n\n/**\n * Clearcoat Materials Extension\n *\n * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_clearcoat\n */\nfunction GLTFMaterialsClearcoatExtension(parser) {\n  this.parser = parser\n  this.name = EXTENSIONS.KHR_MATERIALS_CLEARCOAT\n}\n\nGLTFMaterialsClearcoatExtension.prototype.getMaterialType = function (materialIndex) {\n  var parser = this.parser\n  var materialDef = parser.json.materials[materialIndex]\n\n  if (!materialDef.extensions || !materialDef.extensions[this.name]) return null\n\n  return THREE.MeshPhysicalMaterial\n}\n\nGLTFMaterialsClearcoatExtension.prototype.extendMaterialParams = function (materialIndex, materialParams) {\n  var parser = this.parser\n  var materialDef = parser.json.materials[materialIndex]\n\n  if (!materialDef.extensions || !materialDef.extensions[this.name]) {\n    return Promise.resolve()\n  }\n\n  var pending = []\n\n  var extension = materialDef.extensions[this.name]\n\n  if (extension.clearcoatFactor !== undefined) {\n    materialParams.clearcoat = extension.clearcoatFactor\n  }\n\n  if (extension.clearcoatRoughnessFactor !== undefined) {\n    materialParams.clearcoatRoughness = extension.clearcoatRoughnessFactor\n  }\n\n  if (extension.clearcoatNormalTexture !== undefined) {\n    if (extension.clearcoatNormalTexture.scale !== undefined) {\n      var scale = extension.clearcoatNormalTexture.scale\n      materialParams.clearcoatNormalScale = new THREE.Vector2(scale, scale)\n    }\n  }\n\n  return Promise.all(pending)\n}\n\n/**\n * Transmission Materials Extension\n *\n * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_transmission\n * Draft: https://github.com/KhronosGroup/glTF/pull/1698\n */\nfunction GLTFMaterialsTransmissionExtension(parser) {\n  this.parser = parser\n  this.name = EXTENSIONS.KHR_MATERIALS_TRANSMISSION\n}\n\nGLTFMaterialsTransmissionExtension.prototype.getMaterialType = function (materialIndex) {\n  var parser = this.parser\n  var materialDef = parser.json.materials[materialIndex]\n\n  if (!materialDef.extensions || !materialDef.extensions[this.name]) return null\n\n  return THREE.MeshPhysicalMaterial\n}\n\nGLTFMaterialsTransmissionExtension.prototype.extendMaterialParams = function (materialIndex, materialParams) {\n  var parser = this.parser\n  var materialDef = parser.json.materials[materialIndex]\n\n  if (!materialDef.extensions || !materialDef.extensions[this.name]) {\n    return Promise.resolve()\n  }\n\n  var pending = []\n\n  var extension = materialDef.extensions[this.name]\n\n  if (extension.transmissionFactor !== undefined) {\n    materialParams.transmission = extension.transmissionFactor\n  }\n\n  return Promise.all(pending)\n}\n\n/**\n * BasisU Texture Extension\n *\n * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_texture_basisu\n * (draft PR https://github.com/KhronosGroup/glTF/pull/1751)\n */\nfunction GLTFTextureBasisUExtension(parser) {\n  this.parser = parser\n  this.name = EXTENSIONS.KHR_TEXTURE_BASISU\n}\n\nGLTFTextureBasisUExtension.prototype.loadTexture = function (textureIndex) {\n  return Promise.resolve(new THREE.Texture())\n}\n\n/**\n * GPU Instancing Extension\n *\n * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/EXT_mesh_gpu_instancing\n *\n */\nclass GLTFMeshGpuInstancing {\n  constructor(parser) {\n    this.name = EXTENSIONS.EXT_MESH_GPU_INSTANCING\n    this.parser = parser\n  }\n\n  createNodeMesh(nodeIndex) {\n    const json = this.parser.json\n    const nodeDef = json.nodes[nodeIndex]\n\n    if (!nodeDef.extensions || !nodeDef.extensions[this.name] || nodeDef.mesh === undefined) {\n      return null\n    }\n\n    const meshDef = json.meshes[nodeDef.mesh]\n\n    // No Points or Lines + Instancing support yet\n    for (const primitive of meshDef.primitives) {\n      if (\n        primitive.mode !== WEBGL_CONSTANTS.TRIANGLES &&\n        primitive.mode !== WEBGL_CONSTANTS.TRIANGLE_STRIP &&\n        primitive.mode !== WEBGL_CONSTANTS.TRIANGLE_FAN &&\n        primitive.mode !== undefined\n      ) {\n        return null\n      }\n    }\n\n    const extensionDef = nodeDef.extensions[this.name]\n    const attributesDef = extensionDef.attributes\n    // @TODO: Can we support InstancedMesh + SkinnedMesh?\n    const pending = []\n    const attributes = {}\n\n    for (const key in attributesDef) {\n      pending.push(\n        this.parser.getDependency('accessor', attributesDef[key]).then((accessor) => {\n          attributes[key] = accessor\n          return attributes[key]\n        })\n      )\n    }\n    if (pending.length < 1) {\n      return null\n    }\n    pending.push(this.parser.createNodeMesh(nodeIndex))\n\n    return Promise.all(pending).then((results) => {\n      const nodeObject = results.pop()\n      const meshes = nodeObject.isGroup ? nodeObject.children : [nodeObject]\n      const count = results[0].count // All attribute counts should be same\n\n      const instancedMeshes = []\n      for (const mesh of meshes) {\n        // Temporal variables\n        const m = new THREE.Matrix4()\n        const p = new THREE.Vector3()\n        const q = new THREE.Quaternion()\n        const s = new THREE.Vector3(1, 1, 1)\n        const instancedMesh = new THREE.InstancedMesh(mesh.geometry, mesh.material, count)\n\n        for (let i = 0; i < count; i++) {\n          if (attributes.TRANSLATION) {\n            p.fromBufferAttribute(attributes.TRANSLATION, i)\n          }\n          if (attributes.ROTATION) {\n            q.fromBufferAttribute(attributes.ROTATION, i)\n          }\n          if (attributes.SCALE) {\n            s.fromBufferAttribute(attributes.SCALE, i)\n          }\n          instancedMesh.setMatrixAt(i, m.compose(p, q, s))\n        }\n\n        // Add instance attributes to the geometry, excluding TRS.\n        for (const attributeName in attributes) {\n          if (attributeName !== 'TRANSLATION' && attributeName !== 'ROTATION' && attributeName !== 'SCALE') {\n            mesh.geometry.setAttribute(attributeName, attributes[attributeName])\n          }\n        }\n\n        // Just in case\n        THREE.Object3D.prototype.copy.call(instancedMesh, mesh)\n        this.parser.assignFinalMaterial(instancedMesh)\n        instancedMeshes.push(instancedMesh)\n      }\n      if (nodeObject.isGroup) {\n        nodeObject.clear()\n        nodeObject.add(...instancedMeshes)\n        return nodeObject\n      }\n      return instancedMeshes[0]\n    })\n  }\n}\n\n/* BINARY EXTENSION */\nvar BINARY_EXTENSION_HEADER_MAGIC = 'glTF'\nvar BINARY_EXTENSION_HEADER_LENGTH = 12\nvar BINARY_EXTENSION_CHUNK_TYPES = { JSON: 0x4e4f534a, BIN: 0x004e4942 }\n\nfunction GLTFBinaryExtension(data) {\n  this.name = EXTENSIONS.KHR_BINARY_GLTF\n  this.content = null\n  this.body = null\n\n  var headerView = new DataView(data, 0, BINARY_EXTENSION_HEADER_LENGTH)\n\n  this.header = {\n    magic: THREE.LoaderUtils.decodeText(new Uint8Array(data.slice(0, 4))),\n    version: headerView.getUint32(4, true),\n    length: headerView.getUint32(8, true),\n  }\n\n  if (this.header.magic !== BINARY_EXTENSION_HEADER_MAGIC) {\n    throw new Error('THREE.GLTFLoader: Unsupported glTF-Binary header.')\n  } else if (this.header.version < 2.0) {\n    throw new Error('THREE.GLTFLoader: Legacy binary file detected.')\n  }\n\n  var chunkView = new DataView(data, BINARY_EXTENSION_HEADER_LENGTH)\n  var chunkIndex = 0\n\n  while (chunkIndex < chunkView.byteLength) {\n    var chunkLength = chunkView.getUint32(chunkIndex, true)\n    chunkIndex += 4\n\n    var chunkType = chunkView.getUint32(chunkIndex, true)\n    chunkIndex += 4\n\n    if (chunkType === BINARY_EXTENSION_CHUNK_TYPES.JSON) {\n      var contentArray = new Uint8Array(data, BINARY_EXTENSION_HEADER_LENGTH + chunkIndex, chunkLength)\n      this.content = THREE.LoaderUtils.decodeText(contentArray)\n    } else if (chunkType === BINARY_EXTENSION_CHUNK_TYPES.BIN) {\n      var byteOffset = BINARY_EXTENSION_HEADER_LENGTH + chunkIndex\n      this.body = data.slice(byteOffset, byteOffset + chunkLength)\n    }\n\n    // Clients must ignore chunks with unknown types.\n\n    chunkIndex += chunkLength\n  }\n\n  if (this.content === null) {\n    throw new Error('THREE.GLTFLoader: JSON content not found.')\n  }\n}\n\n/**\n * DRACO Mesh Compression Extension\n *\n * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_draco_mesh_compression\n */\nfunction GLTFDracoMeshCompressionExtension(json, dracoLoader) {\n  if (!dracoLoader) {\n    throw new Error('THREE.GLTFLoader: No DRACOLoader instance provided.')\n  }\n\n  this.name = EXTENSIONS.KHR_DRACO_MESH_COMPRESSION\n  this.json = json\n  this.dracoLoader = dracoLoader\n}\n\nGLTFDracoMeshCompressionExtension.prototype.decodePrimitive = function (primitive, parser) {\n  var json = this.json\n  var dracoLoader = this.dracoLoader\n  var bufferViewIndex = primitive.extensions[this.name].bufferView\n  var gltfAttributeMap = primitive.extensions[this.name].attributes\n  var threeAttributeMap = {}\n  var attributeNormalizedMap = {}\n  var attributeTypeMap = {}\n\n  for (var attributeName in gltfAttributeMap) {\n    var threeAttributeName = ATTRIBUTES[attributeName] || attributeName.toLowerCase()\n\n    threeAttributeMap[threeAttributeName] = gltfAttributeMap[attributeName]\n  }\n\n  for (attributeName in primitive.attributes) {\n    var threeAttributeName = ATTRIBUTES[attributeName] || attributeName.toLowerCase()\n\n    if (gltfAttributeMap[attributeName] !== undefined) {\n      var accessorDef = json.accessors[primitive.attributes[attributeName]]\n      var componentType = WEBGL_COMPONENT_TYPES[accessorDef.componentType]\n\n      attributeTypeMap[threeAttributeName] = componentType\n      attributeNormalizedMap[threeAttributeName] = accessorDef.normalized === true\n    }\n  }\n\n  return parser.getDependency('bufferView', bufferViewIndex).then(function (bufferView) {\n    return new Promise(function (resolve) {\n      dracoLoader.decodeDracoFile(\n        bufferView,\n        function (geometry) {\n          for (var attributeName in geometry.attributes) {\n            var attribute = geometry.attributes[attributeName]\n            var normalized = attributeNormalizedMap[attributeName]\n\n            if (normalized !== undefined) attribute.normalized = normalized\n          }\n\n          resolve(geometry)\n        },\n        threeAttributeMap,\n        attributeTypeMap\n      )\n    })\n  })\n}\n\n/**\n * Texture Transform Extension\n *\n * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_texture_transform\n */\nfunction GLTFTextureTransformExtension() {\n  this.name = EXTENSIONS.KHR_TEXTURE_TRANSFORM\n}\n\nGLTFTextureTransformExtension.prototype.extendTexture = function (texture, transform) {\n  texture = texture.clone()\n\n  if (transform.offset !== undefined) {\n    texture.offset.fromArray(transform.offset)\n  }\n\n  if (transform.rotation !== undefined) {\n    texture.rotation = transform.rotation\n  }\n\n  if (transform.scale !== undefined) {\n    texture.repeat.fromArray(transform.scale)\n  }\n\n  if (transform.texCoord !== undefined) {\n    console.warn('THREE.GLTFLoader: Custom UV sets in \"' + this.name + '\" extension not yet supported.')\n  }\n\n  texture.needsUpdate = true\n\n  return texture\n}\n\n/**\n * Specular-Glossiness Extension\n *\n * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_pbrSpecularGlossiness\n */\n\nfunction GLTFMaterialsPbrSpecularGlossinessExtension() {\n  return {\n    name: EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS,\n\n    specularGlossinessParams: [\n      'color',\n      'map',\n      'lightMap',\n      'lightMapIntensity',\n      'aoMap',\n      'aoMapIntensity',\n      'emissive',\n      'emissiveIntensity',\n      'emissiveMap',\n      'bumpMap',\n      'bumpScale',\n      'normalMap',\n      'normalMapType',\n      'displacementMap',\n      'displacementScale',\n      'displacementBias',\n      'specularMap',\n      'specular',\n      'glossinessMap',\n      'glossiness',\n      'alphaMap',\n      'envMap',\n      'envMapIntensity',\n      'refractionRatio',\n    ],\n\n    getMaterialType: function () {\n      return THREE.MeshStandardMaterial\n    },\n\n    extendParams: function (materialParams, materialDef, parser) {\n      var pbrSpecularGlossiness = materialDef.extensions[this.name]\n\n      materialParams.color = new THREE.Color(1.0, 1.0, 1.0)\n      materialParams.opacity = 1.0\n\n      var pending = []\n\n      if (Array.isArray(pbrSpecularGlossiness.diffuseFactor)) {\n        var array = pbrSpecularGlossiness.diffuseFactor\n\n        materialParams.color.fromArray(array)\n        materialParams.opacity = array[3]\n      }\n\n      materialParams.emissive = new THREE.Color(0.0, 0.0, 0.0)\n      materialParams.glossiness =\n        pbrSpecularGlossiness.glossinessFactor !== undefined ? pbrSpecularGlossiness.glossinessFactor : 1.0\n      materialParams.specular = new THREE.Color(1.0, 1.0, 1.0)\n\n      if (Array.isArray(pbrSpecularGlossiness.specularFactor)) {\n        materialParams.specular.fromArray(pbrSpecularGlossiness.specularFactor)\n      }\n\n      return Promise.all(pending)\n    },\n\n    createMaterial: function (materialParams) {\n      var material = new THREE.MeshStandardMaterial(materialParams)\n      material.fog = true\n\n      material.color = materialParams.color\n\n      material.map = materialParams.map === undefined ? null : materialParams.map\n\n      material.lightMap = null\n      material.lightMapIntensity = 1.0\n\n      material.aoMap = materialParams.aoMap === undefined ? null : materialParams.aoMap\n      material.aoMapIntensity = 1.0\n\n      material.emissive = materialParams.emissive\n      material.emissiveIntensity = 1.0\n      material.emissiveMap = materialParams.emissiveMap === undefined ? null : materialParams.emissiveMap\n\n      material.bumpMap = materialParams.bumpMap === undefined ? null : materialParams.bumpMap\n      material.bumpScale = 1\n\n      material.normalMap = materialParams.normalMap === undefined ? null : materialParams.normalMap\n      material.normalMapType = THREE.TangentSpaceNormalMap\n\n      if (materialParams.normalScale) material.normalScale = materialParams.normalScale\n\n      material.displacementMap = null\n      material.displacementScale = 1\n      material.displacementBias = 0\n\n      material.specularMap = materialParams.specularMap === undefined ? null : materialParams.specularMap\n      material.specular = materialParams.specular\n\n      material.glossinessMap = materialParams.glossinessMap === undefined ? null : materialParams.glossinessMap\n      material.glossiness = materialParams.glossiness\n\n      material.alphaMap = null\n\n      material.envMap = materialParams.envMap === undefined ? null : materialParams.envMap\n      material.envMapIntensity = 1.0\n\n      material.refractionRatio = 0.98\n\n      return material\n    },\n  }\n}\n\n/**\n * Mesh Quantization Extension\n *\n * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_mesh_quantization\n */\nfunction GLTFMeshQuantizationExtension() {\n  this.name = EXTENSIONS.KHR_MESH_QUANTIZATION\n}\n\n/*********************************/\n/********** INTERPOLATION ********/\n/*********************************/\n\n// Spline Interpolation\n// Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#appendix-c-spline-interpolation\nfunction GLTFCubicSplineInterpolant(parameterPositions, sampleValues, sampleSize, resultBuffer) {\n  THREE.Interpolant.call(this, parameterPositions, sampleValues, sampleSize, resultBuffer)\n}\n\nGLTFCubicSplineInterpolant.prototype = Object.create(THREE.Interpolant.prototype)\nGLTFCubicSplineInterpolant.prototype.constructor = GLTFCubicSplineInterpolant\n\nGLTFCubicSplineInterpolant.prototype.copySampleValue_ = function (index) {\n  // Copies a sample value to the result buffer. See description of glTF\n  // CUBICSPLINE values layout in interpolate_() function below.\n\n  var result = this.resultBuffer,\n    values = this.sampleValues,\n    valueSize = this.valueSize,\n    offset = index * valueSize * 3 + valueSize\n\n  for (var i = 0; i !== valueSize; i++) {\n    result[i] = values[offset + i]\n  }\n\n  return result\n}\n\nGLTFCubicSplineInterpolant.prototype.beforeStart_ = GLTFCubicSplineInterpolant.prototype.copySampleValue_\n\nGLTFCubicSplineInterpolant.prototype.afterEnd_ = GLTFCubicSplineInterpolant.prototype.copySampleValue_\n\nGLTFCubicSplineInterpolant.prototype.interpolate_ = function (i1, t0, t, t1) {\n  var result = this.resultBuffer\n  var values = this.sampleValues\n  var stride = this.valueSize\n\n  var stride2 = stride * 2\n  var stride3 = stride * 3\n\n  var td = t1 - t0\n\n  var p = (t - t0) / td\n  var pp = p * p\n  var ppp = pp * p\n\n  var offset1 = i1 * stride3\n  var offset0 = offset1 - stride3\n\n  var s2 = -2 * ppp + 3 * pp\n  var s3 = ppp - pp\n  var s0 = 1 - s2\n  var s1 = s3 - pp + p\n\n  // Layout of keyframe output values for CUBICSPLINE animations:\n  //   [ inTangent_1, splineVertex_1, outTangent_1, inTangent_2, splineVertex_2, ... ]\n  for (var i = 0; i !== stride; i++) {\n    var p0 = values[offset0 + i + stride] // splineVertex_k\n    var m0 = values[offset0 + i + stride2] * td // outTangent_k * (t_k+1 - t_k)\n    var p1 = values[offset1 + i + stride] // splineVertex_k+1\n    var m1 = values[offset1 + i] * td // inTangent_k+1 * (t_k+1 - t_k)\n\n    result[i] = s0 * p0 + s1 * m0 + s2 * p1 + s3 * m1\n  }\n\n  return result\n}\n\n/*********************************/\n/********** INTERNALS ************/\n/*********************************/\n\n/* CONSTANTS */\n\nvar WEBGL_CONSTANTS = {\n  FLOAT: 5126,\n  //FLOAT_MAT2: 35674,\n  FLOAT_MAT3: 35675,\n  FLOAT_MAT4: 35676,\n  FLOAT_VEC2: 35664,\n  FLOAT_VEC3: 35665,\n  FLOAT_VEC4: 35666,\n  LINEAR: 9729,\n  REPEAT: 10497,\n  SAMPLER_2D: 35678,\n  POINTS: 0,\n  LINES: 1,\n  LINE_LOOP: 2,\n  LINE_STRIP: 3,\n  TRIANGLES: 4,\n  TRIANGLE_STRIP: 5,\n  TRIANGLE_FAN: 6,\n  UNSIGNED_BYTE: 5121,\n  UNSIGNED_SHORT: 5123,\n}\n\nvar WEBGL_COMPONENT_TYPES = {\n  5120: Int8Array,\n  5121: Uint8Array,\n  5122: Int16Array,\n  5123: Uint16Array,\n  5125: Uint32Array,\n  5126: Float32Array,\n}\n\nvar WEBGL_FILTERS = {\n  9728: THREE.NearestFilter,\n  9729: THREE.LinearFilter,\n  9984: THREE.NearestMipmapNearestFilter,\n  9985: THREE.LinearMipmapNearestFilter,\n  9986: THREE.NearestMipmapLinearFilter,\n  9987: THREE.LinearMipmapLinearFilter,\n}\n\nvar WEBGL_WRAPPINGS = {\n  33071: THREE.ClampToEdgeWrapping,\n  33648: THREE.MirroredRepeatWrapping,\n  10497: THREE.RepeatWrapping,\n}\n\nvar WEBGL_TYPE_SIZES = {\n  SCALAR: 1,\n  VEC2: 2,\n  VEC3: 3,\n  VEC4: 4,\n  MAT2: 4,\n  MAT3: 9,\n  MAT4: 16,\n}\n\nvar ATTRIBUTES = {\n  POSITION: 'position',\n  NORMAL: 'normal',\n  TANGENT: 'tangent',\n  TEXCOORD_0: 'uv',\n  TEXCOORD_1: 'uv2',\n  COLOR_0: 'color',\n  WEIGHTS_0: 'skinWeight',\n  JOINTS_0: 'skinIndex',\n}\n\nvar PATH_PROPERTIES = {\n  scale: 'scale',\n  translation: 'position',\n  rotation: 'quaternion',\n  weights: 'morphTargetInfluences',\n}\n\nvar INTERPOLATION = {\n  CUBICSPLINE: undefined, // We use a custom interpolant (GLTFCubicSplineInterpolation) for CUBICSPLINE tracks. Each\n  // keyframe track will be initialized with a default interpolation type, then modified.\n  LINEAR: THREE.InterpolateLinear,\n  STEP: THREE.InterpolateDiscrete,\n}\n\nvar ALPHA_MODES = {\n  OPAQUE: 'OPAQUE',\n  MASK: 'MASK',\n  BLEND: 'BLEND',\n}\n\n/* UTILITY FUNCTIONS */\n\nfunction resolveURL(url, path) {\n  // Invalid URL\n  if (typeof url !== 'string' || url === '') return ''\n\n  // Host Relative URL\n  if (/^https?:\\/\\//i.test(path) && /^\\//.test(url)) {\n    path = path.replace(/(^https?:\\/\\/[^\\/]+).*/i, '$1')\n  }\n\n  // Absolute URL http://,https://,//\n  if (/^(https?:)?\\/\\//i.test(url)) return url\n\n  // Data URI\n  if (/^data:.*,.*$/i.test(url)) return url\n\n  // Blob URL\n  if (/^blob:.*$/i.test(url)) return url\n\n  // Relative URL\n  return path + url\n}\n\n/**\n * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#default-material\n */\nfunction createDefaultMaterial(cache) {\n  if (cache['DefaultMaterial'] === undefined) {\n    cache['DefaultMaterial'] = new THREE.MeshStandardMaterial({\n      color: 0xffffff,\n      emissive: 0x000000,\n      metalness: 1,\n      roughness: 1,\n      transparent: false,\n      depthTest: true,\n      side: THREE.FrontSide,\n    })\n  }\n\n  return cache['DefaultMaterial']\n}\n\nfunction addUnknownExtensionsToUserData(knownExtensions, object, objectDef) {\n  // Add unknown glTF extensions to an object's userData.\n\n  for (var name in objectDef.extensions) {\n    if (knownExtensions[name] === undefined) {\n      object.userData.gltfExtensions = object.userData.gltfExtensions || {}\n      object.userData.gltfExtensions[name] = objectDef.extensions[name]\n    }\n  }\n}\n\n/**\n * @param {THREE.Object3D|THREE.Material|THREE.BufferGeometry} object\n * @param {GLTF.definition} gltfDef\n */\nfunction assignExtrasToUserData(object, gltfDef) {\n  if (gltfDef.extras !== undefined) {\n    if (typeof gltfDef.extras === 'object') {\n      Object.assign(object.userData, gltfDef.extras)\n    } else {\n      console.warn('THREE.GLTFLoader: Ignoring primitive type .extras, ' + gltfDef.extras)\n    }\n  }\n}\n\n/**\n * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#morph-targets\n *\n * @param {THREE.BufferGeometry} geometry\n * @param {Array<GLTF.Target>} targets\n * @param {GLTFParser} parser\n * @return {Promise<THREE.BufferGeometry>}\n */\nfunction addMorphTargets(geometry, targets, parser) {\n  var hasMorphPosition = false\n  var hasMorphNormal = false\n\n  for (var i = 0, il = targets.length; i < il; i++) {\n    var target = targets[i]\n\n    if (target.POSITION !== undefined) hasMorphPosition = true\n    if (target.NORMAL !== undefined) hasMorphNormal = true\n\n    if (hasMorphPosition && hasMorphNormal) break\n  }\n\n  if (!hasMorphPosition && !hasMorphNormal) return Promise.resolve(geometry)\n\n  var pendingPositionAccessors = []\n  var pendingNormalAccessors = []\n\n  for (var i = 0, il = targets.length; i < il; i++) {\n    var target = targets[i]\n\n    if (hasMorphPosition) {\n      var pendingAccessor =\n        target.POSITION !== undefined ? parser.getDependency('accessor', target.POSITION) : geometry.attributes.position\n\n      pendingPositionAccessors.push(pendingAccessor)\n    }\n\n    if (hasMorphNormal) {\n      var pendingAccessor =\n        target.NORMAL !== undefined ? parser.getDependency('accessor', target.NORMAL) : geometry.attributes.normal\n\n      pendingNormalAccessors.push(pendingAccessor)\n    }\n  }\n\n  return Promise.all([Promise.all(pendingPositionAccessors), Promise.all(pendingNormalAccessors)]).then(function (\n    accessors\n  ) {\n    var morphPositions = accessors[0]\n    var morphNormals = accessors[1]\n\n    if (hasMorphPosition) geometry.morphAttributes.position = morphPositions\n    if (hasMorphNormal) geometry.morphAttributes.normal = morphNormals\n    geometry.morphTargetsRelative = true\n\n    return geometry\n  })\n}\n\nfunction createPrimitiveKey(primitiveDef) {\n  var dracoExtension = primitiveDef.extensions && primitiveDef.extensions[EXTENSIONS.KHR_DRACO_MESH_COMPRESSION]\n  var geometryKey\n\n  if (dracoExtension) {\n    geometryKey =\n      'draco:' +\n      dracoExtension.bufferView +\n      ':' +\n      dracoExtension.indices +\n      ':' +\n      createAttributesKey(dracoExtension.attributes)\n  } else {\n    geometryKey = primitiveDef.indices + ':' + createAttributesKey(primitiveDef.attributes) + ':' + primitiveDef.mode\n  }\n\n  return geometryKey\n}\n\nfunction createAttributesKey(attributes) {\n  var attributesKey = ''\n\n  var keys = Object.keys(attributes).sort()\n\n  for (var i = 0, il = keys.length; i < il; i++) {\n    attributesKey += keys[i] + ':' + attributes[keys[i]] + ';'\n  }\n\n  return attributesKey\n}\n\n/* GLTF PARSER */\n\nfunction GLTFParser(json, options) {\n  this.json = json || {}\n  this.extensions = {}\n  this.plugins = {}\n  this.options = options || {}\n\n  // loader object cache\n  this.cache = new GLTFRegistry()\n\n  // associations between Three.js objects and glTF elements\n  this.associations = new Map()\n\n  // BufferGeometry caching\n  this.primitiveCache = {}\n\n  // Object3D instance caches\n  this.meshCache = { refs: {}, uses: {} }\n  this.cameraCache = { refs: {}, uses: {} }\n  this.lightCache = { refs: {}, uses: {} }\n\n  // Track node names, to ensure no duplicates\n  this.nodeNamesUsed = {}\n\n  // Use an ImageBitmapLoader if imageBitmaps are supported. Moves much of the\n  // expensive work of uploading a texture to the GPU off the main thread.\n  if (typeof createImageBitmap !== 'undefined' && /Firefox/.test(navigator.userAgent) === false) {\n    this.textureLoader = new THREE.ImageBitmapLoader(this.options.manager)\n  } else {\n    this.textureLoader = new THREE.TextureLoader(this.options.manager)\n  }\n\n  this.textureLoader.setCrossOrigin(this.options.crossOrigin)\n\n  this.fileLoader = new THREE.FileLoader(this.options.manager)\n  this.fileLoader.setResponseType('arraybuffer')\n\n  if (this.options.crossOrigin === 'use-credentials') {\n    this.fileLoader.setWithCredentials(true)\n  }\n}\n\nGLTFParser.prototype.setExtensions = function (extensions) {\n  this.extensions = extensions\n}\n\nGLTFParser.prototype.setPlugins = function (plugins) {\n  this.plugins = plugins\n}\n\nGLTFParser.prototype.parse = function (onLoad, onError) {\n  var parser = this\n  var json = this.json\n  var extensions = this.extensions\n\n  // Clear the loader cache\n  this.cache.removeAll()\n\n  // Mark the special nodes/meshes in json for efficient parse\n  this._invokeAll(function (ext) {\n    return ext._markDefs && ext._markDefs()\n  })\n\n  Promise.all([this.getDependencies('scene'), this.getDependencies('animation'), this.getDependencies('camera')])\n    .then(function (dependencies) {\n      var result = {\n        scene: dependencies[0][json.scene || 0],\n        scenes: dependencies[0],\n        animations: dependencies[1],\n        cameras: dependencies[2],\n        asset: json.asset,\n        parser: parser,\n        userData: {},\n      }\n\n      addUnknownExtensionsToUserData(extensions, result, json)\n\n      assignExtrasToUserData(result, json)\n\n      onLoad(result)\n    })\n    .catch(onError)\n}\n\n/**\n * Marks the special nodes/meshes in json for efficient parse.\n */\nGLTFParser.prototype._markDefs = function () {\n  var nodeDefs = this.json.nodes || []\n  var skinDefs = this.json.skins || []\n  var meshDefs = this.json.meshes || []\n\n  // Nothing in the node definition indicates whether it is a Bone or an\n  // Object3D. Use the skins' joint references to mark bones.\n  for (var skinIndex = 0, skinLength = skinDefs.length; skinIndex < skinLength; skinIndex++) {\n    var joints = skinDefs[skinIndex].joints\n\n    for (var i = 0, il = joints.length; i < il; i++) {\n      nodeDefs[joints[i]].isBone = true\n    }\n  }\n\n  // Iterate over all nodes, marking references to shared resources,\n  // as well as skeleton joints.\n  for (var nodeIndex = 0, nodeLength = nodeDefs.length; nodeIndex < nodeLength; nodeIndex++) {\n    var nodeDef = nodeDefs[nodeIndex]\n\n    if (nodeDef.mesh !== undefined) {\n      this._addNodeRef(this.meshCache, nodeDef.mesh)\n\n      // Nothing in the mesh definition indicates whether it is\n      // a SkinnedMesh or Mesh. Use the node's mesh reference\n      // to mark SkinnedMesh if node has skin.\n      if (nodeDef.skin !== undefined) {\n        meshDefs[nodeDef.mesh].isSkinnedMesh = true\n      }\n    }\n\n    if (nodeDef.camera !== undefined) {\n      this._addNodeRef(this.cameraCache, nodeDef.camera)\n    }\n  }\n}\n\n/**\n * Counts references to shared node / Object3D resources. These resources\n * can be reused, or \"instantiated\", at multiple nodes in the scene\n * hierarchy. Mesh, Camera, and Light instances are instantiated and must\n * be marked. Non-scenegraph resources (like Materials, Geometries, and\n * Textures) can be reused directly and are not marked here.\n *\n * Example: CesiumMilkTruck sample model reuses \"Wheel\" meshes.\n */\nGLTFParser.prototype._addNodeRef = function (cache, index) {\n  if (index === undefined) return\n\n  if (cache.refs[index] === undefined) {\n    cache.refs[index] = cache.uses[index] = 0\n  }\n\n  cache.refs[index]++\n}\n\n/** Returns a reference to a shared resource, cloning it if necessary. */\nGLTFParser.prototype._getNodeRef = function (cache, index, object) {\n  if (cache.refs[index] <= 1) return object\n\n  var ref = object.clone()\n\n  ref.name += '_instance_' + cache.uses[index]++\n\n  return ref\n}\n\nGLTFParser.prototype._invokeOne = function (func) {\n  var extensions = Object.values(this.plugins)\n  extensions.push(this)\n\n  for (var i = 0; i < extensions.length; i++) {\n    var result = func(extensions[i])\n\n    if (result) return result\n  }\n}\n\nGLTFParser.prototype._invokeAll = function (func) {\n  var extensions = Object.values(this.plugins)\n  extensions.unshift(this)\n\n  var pending = []\n\n  for (var i = 0; i < extensions.length; i++) {\n    var result = func(extensions[i])\n\n    if (result) pending.push(result)\n  }\n\n  return pending\n}\n\n/**\n * Requests the specified dependency asynchronously, with caching.\n * @param {string} type\n * @param {number} index\n * @return {Promise<THREE.Object3D|THREE.Material|THREE.Texture|THREE.AnimationClip|ArrayBuffer|Object>}\n */\nGLTFParser.prototype.getDependency = function (type, index) {\n  var cacheKey = type + ':' + index\n  var dependency = this.cache.get(cacheKey)\n\n  if (!dependency) {\n    switch (type) {\n      case 'scene':\n        dependency = this.loadScene(index)\n        break\n\n      case 'node':\n        dependency = this.loadNode(index)\n        break\n\n      case 'mesh':\n        dependency = this._invokeOne(function (ext) {\n          return ext.loadMesh && ext.loadMesh(index)\n        })\n        break\n\n      case 'accessor':\n        dependency = this.loadAccessor(index)\n        break\n\n      case 'bufferView':\n        dependency = Promise.resolve(new Float32Array(0))\n        break\n\n      case 'buffer':\n        dependency = Promise.resolve(new Float32Array(0))\n        break\n\n      case 'material':\n        dependency = this._invokeOne(function (ext) {\n          return ext.loadMaterial && ext.loadMaterial(index)\n        })\n        break\n\n      case 'skin':\n        dependency = this.loadSkin(index)\n        break\n\n      case 'animation':\n        dependency = this.loadAnimation(index)\n        break\n\n      case 'camera':\n        dependency = this.loadCamera(index)\n        break\n\n      default:\n        throw new Error('Unknown type: ' + type)\n    }\n\n    this.cache.add(cacheKey, dependency)\n  }\n\n  return dependency\n}\n\n/**\n * Requests all dependencies of the specified type asynchronously, with caching.\n * @param {string} type\n * @return {Promise<Array<Object>>}\n */\nGLTFParser.prototype.getDependencies = function (type) {\n  var dependencies = this.cache.get(type)\n\n  if (!dependencies) {\n    var parser = this\n    var defs = this.json[type + (type === 'mesh' ? 'es' : 's')] || []\n\n    dependencies = Promise.all(\n      defs.map(function (def, index) {\n        return parser.getDependency(type, index)\n      })\n    )\n\n    this.cache.add(type, dependencies)\n  }\n\n  return dependencies\n}\n\n/**\n * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#buffers-and-buffer-views\n * @param {number} bufferIndex\n * @return {Promise<ArrayBuffer>}\n */\nGLTFParser.prototype.loadBuffer = function (bufferIndex) {\n  var bufferDef = this.json.buffers[bufferIndex]\n  var loader = this.fileLoader\n\n  if (bufferDef.type && bufferDef.type !== 'arraybuffer') {\n    throw new Error('THREE.GLTFLoader: ' + bufferDef.type + ' buffer type is not supported.')\n  }\n\n  // If present, GLB container is required to be the first buffer.\n  if (bufferDef.uri === undefined && bufferIndex === 0) {\n    return Promise.resolve(this.extensions[EXTENSIONS.KHR_BINARY_GLTF].body)\n  }\n\n  var options = this.options\n\n  return new Promise(function (resolve, reject) {\n    loader.load(resolveURL(bufferDef.uri, options.path), resolve, undefined, function () {\n      reject(new Error('THREE.GLTFLoader: Failed to load buffer \"' + bufferDef.uri + '\".'))\n    })\n  })\n}\n\n/**\n * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#buffers-and-buffer-views\n * @param {number} bufferViewIndex\n * @return {Promise<ArrayBuffer>}\n */\nGLTFParser.prototype.loadBufferView = function (bufferViewIndex) {\n  var bufferViewDef = this.json.bufferViews[bufferViewIndex]\n\n  return this.getDependency('buffer', bufferViewDef.buffer).then(function (buffer) {\n    var byteLength = bufferViewDef.byteLength || 0\n    var byteOffset = bufferViewDef.byteOffset || 0\n    return buffer.slice(byteOffset, byteOffset + byteLength)\n  })\n}\n\n/**\n * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#accessors\n * @param {number} accessorIndex\n * @return {Promise<THREE.BufferAttribute|THREE.InterleavedBufferAttribute>}\n */\nGLTFParser.prototype.loadAccessor = function (accessorIndex) {\n  var parser = this\n  var json = this.json\n\n  var accessorDef = this.json.accessors[accessorIndex]\n\n  if (accessorDef.bufferView === undefined && accessorDef.sparse === undefined) {\n    // Ignore empty accessors, which may be used to declare runtime\n    // information about attributes coming from another source (e.g. Draco\n    // compression extension).\n    return Promise.resolve(null)\n  }\n\n  var pendingBufferViews = []\n\n  if (accessorDef.bufferView !== undefined) {\n    pendingBufferViews.push(this.getDependency('bufferView', accessorDef.bufferView))\n  } else {\n    pendingBufferViews.push(null)\n  }\n\n  if (accessorDef.sparse !== undefined) {\n    pendingBufferViews.push(this.getDependency('bufferView', accessorDef.sparse.indices.bufferView))\n    pendingBufferViews.push(this.getDependency('bufferView', accessorDef.sparse.values.bufferView))\n  }\n\n  return Promise.all(pendingBufferViews).then(function (bufferViews) {\n    var bufferView = bufferViews[0]\n\n    var itemSize = WEBGL_TYPE_SIZES[accessorDef.type]\n    var TypedArray = WEBGL_COMPONENT_TYPES[accessorDef.componentType]\n\n    // For VEC3: itemSize is 3, elementBytes is 4, itemBytes is 12.\n    var elementBytes = TypedArray.BYTES_PER_ELEMENT\n    var itemBytes = elementBytes * itemSize\n    var byteOffset = accessorDef.byteOffset || 0\n    var byteStride =\n      accessorDef.bufferView !== undefined ? json.bufferViews[accessorDef.bufferView].byteStride : undefined\n    var normalized = accessorDef.normalized === true\n    var array, bufferAttribute\n\n    // The buffer is not interleaved if the stride is the item size in bytes.\n    if (byteStride && byteStride !== itemBytes) {\n      // Each \"slice\" of the buffer, as defined by 'count' elements of 'byteStride' bytes, gets its own InterleavedBuffer\n      // This makes sure that IBA.count reflects accessor.count properly\n      var ibSlice = Math.floor(byteOffset / byteStride)\n      var ibCacheKey =\n        'InterleavedBuffer:' +\n        accessorDef.bufferView +\n        ':' +\n        accessorDef.componentType +\n        ':' +\n        ibSlice +\n        ':' +\n        accessorDef.count\n      var ib = parser.cache.get(ibCacheKey)\n\n      if (!ib) {\n        array = new TypedArray(bufferView, ibSlice * byteStride, (accessorDef.count * byteStride) / elementBytes)\n\n        // Integer parameters to IB/IBA are in array elements, not bytes.\n        ib = new THREE.InterleavedBuffer(array, byteStride / elementBytes)\n\n        parser.cache.add(ibCacheKey, ib)\n      }\n\n      bufferAttribute = new THREE.InterleavedBufferAttribute(\n        ib,\n        itemSize,\n        (byteOffset % byteStride) / elementBytes,\n        normalized\n      )\n    } else {\n      if (bufferView === null) {\n        array = new TypedArray(accessorDef.count * itemSize)\n      } else {\n        array = new TypedArray(bufferView, byteOffset, accessorDef.count * itemSize)\n      }\n      bufferAttribute = new THREE.BufferAttribute(array, itemSize, normalized)\n    }\n\n    // https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#sparse-accessors\n    if (accessorDef.sparse !== undefined) {\n      var itemSizeIndices = WEBGL_TYPE_SIZES.SCALAR\n      var TypedArrayIndices = WEBGL_COMPONENT_TYPES[accessorDef.sparse.indices.componentType]\n\n      var byteOffsetIndices = accessorDef.sparse.indices.byteOffset || 0\n      var byteOffsetValues = accessorDef.sparse.values.byteOffset || 0\n\n      var sparseIndices = new TypedArrayIndices(\n        bufferViews[1],\n        byteOffsetIndices,\n        accessorDef.sparse.count * itemSizeIndices\n      )\n      var sparseValues = new TypedArray(bufferViews[2], byteOffsetValues, accessorDef.sparse.count * itemSize)\n\n      if (bufferView !== null) {\n        // Avoid modifying the original ArrayBuffer, if the bufferView wasn't initialized with zeroes.\n        bufferAttribute = new THREE.BufferAttribute(\n          bufferAttribute.array.slice(),\n          bufferAttribute.itemSize,\n          bufferAttribute.normalized\n        )\n      }\n\n      for (var i = 0, il = sparseIndices.length; i < il; i++) {\n        var index = sparseIndices[i]\n\n        bufferAttribute.setX(index, sparseValues[i * itemSize])\n        if (itemSize >= 2) bufferAttribute.setY(index, sparseValues[i * itemSize + 1])\n        if (itemSize >= 3) bufferAttribute.setZ(index, sparseValues[i * itemSize + 2])\n        if (itemSize >= 4) bufferAttribute.setW(index, sparseValues[i * itemSize + 3])\n        if (itemSize >= 5) throw new Error('THREE.GLTFLoader: Unsupported itemSize in sparse BufferAttribute.')\n      }\n    }\n\n    if (bufferAttribute.isInterleavedBufferAttribute) {\n      bufferAttribute.data.count = accessorDef.count\n    } else {\n      bufferAttribute.count = accessorDef.count\n    }\n    return bufferAttribute\n  })\n}\n\n/**\n * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#textures\n * @param {number} textureIndex\n * @return {Promise<THREE.Texture>}\n */\nGLTFParser.prototype.loadTexture = function (textureIndex) {\n  return Promise.resolve(new THREE.Texture())\n}\n\n/**\n * Assigns final material to a Mesh, Line, or Points instance. The instance\n * already has a material (generated from the glTF material options alone)\n * but reuse of the same glTF material may require multiple threejs materials\n * to accomodate different primitive types, defines, etc. New materials will\n * be created if necessary, and reused from a cache.\n * @param  {THREE.Object3D} mesh Mesh, Line, or Points instance.\n */\nGLTFParser.prototype.assignFinalMaterial = function (mesh) {\n  var geometry = mesh.geometry\n  var material = mesh.material\n\n  var useVertexTangents = geometry.attributes.tangent !== undefined\n  var useVertexColors = geometry.attributes.color !== undefined\n  var useFlatShading = geometry.attributes.normal === undefined\n  var useSkinning = mesh.isSkinnedMesh === true\n  var useMorphTargets = Object.keys(geometry.morphAttributes).length > 0\n  var useMorphNormals = useMorphTargets && geometry.morphAttributes.normal !== undefined\n\n  if (mesh.isPoints) {\n    var cacheKey = 'PointsMaterial:' + material.uuid\n\n    var pointsMaterial = this.cache.get(cacheKey)\n\n    if (!pointsMaterial) {\n      pointsMaterial = new THREE.PointsMaterial()\n      THREE.Material.prototype.copy.call(pointsMaterial, material)\n      pointsMaterial.color.copy(material.color)\n      pointsMaterial.map = material.map\n      pointsMaterial.sizeAttenuation = false // glTF spec says points should be 1px\n\n      this.cache.add(cacheKey, pointsMaterial)\n    }\n\n    material = pointsMaterial\n  } else if (mesh.isLine) {\n    var cacheKey = 'LineBasicMaterial:' + material.uuid\n\n    var lineMaterial = this.cache.get(cacheKey)\n\n    if (!lineMaterial) {\n      lineMaterial = new THREE.LineBasicMaterial()\n      THREE.Material.prototype.copy.call(lineMaterial, material)\n      lineMaterial.color.copy(material.color)\n\n      this.cache.add(cacheKey, lineMaterial)\n    }\n\n    material = lineMaterial\n  }\n\n  // Clone the material if it will be modified\n  if (useVertexTangents || useVertexColors || useFlatShading || useSkinning || useMorphTargets) {\n    var cacheKey = 'ClonedMaterial:' + material.uuid + ':'\n\n    if (material.isGLTFSpecularGlossinessMaterial) cacheKey += 'specular-glossiness:'\n    if (useSkinning) cacheKey += 'skinning:'\n    if (useVertexTangents) cacheKey += 'vertex-tangents:'\n    if (useVertexColors) cacheKey += 'vertex-colors:'\n    if (useFlatShading) cacheKey += 'flat-shading:'\n    if (useMorphTargets) cacheKey += 'morph-targets:'\n    if (useMorphNormals) cacheKey += 'morph-normals:'\n\n    var cachedMaterial = this.cache.get(cacheKey)\n\n    if (!cachedMaterial) {\n      cachedMaterial = material.clone()\n\n      if (useSkinning) cachedMaterial.skinning = true\n      if (useVertexTangents) cachedMaterial.vertexTangents = true\n      if (useVertexColors) cachedMaterial.vertexColors = true\n      if (useFlatShading) cachedMaterial.flatShading = true\n      if (useMorphTargets) cachedMaterial.morphTargets = true\n      if (useMorphNormals) cachedMaterial.morphNormals = true\n\n      this.cache.add(cacheKey, cachedMaterial)\n\n      this.associations.set(cachedMaterial, this.associations.get(material))\n    }\n\n    material = cachedMaterial\n  }\n\n  // workarounds for mesh and geometry\n\n  if (material.aoMap && geometry.attributes.uv2 === undefined && geometry.attributes.uv !== undefined) {\n    geometry.setAttribute('uv2', geometry.attributes.uv)\n  }\n\n  // https://github.com/mrdoob/three.js/issues/11438#issuecomment-507003995\n  if (material.normalScale && !useVertexTangents) {\n    material.normalScale.y = -material.normalScale.y\n  }\n\n  if (material.clearcoatNormalScale && !useVertexTangents) {\n    material.clearcoatNormalScale.y = -material.clearcoatNormalScale.y\n  }\n\n  mesh.material = material\n}\n\nGLTFParser.prototype.getMaterialType = function (/* materialIndex */) {\n  return THREE.MeshStandardMaterial\n}\n\n/**\n * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#materials\n * @param {number} materialIndex\n * @return {Promise<THREE.Material>}\n */\nGLTFParser.prototype.loadMaterial = function (materialIndex) {\n  var parser = this\n  var json = this.json\n  var extensions = this.extensions\n  var materialDef = json.materials[materialIndex]\n\n  var materialType\n  var materialParams = {}\n  var materialExtensions = materialDef.extensions || {}\n\n  var pending = []\n\n  if (materialExtensions[EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS]) {\n    var sgExtension = extensions[EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS]\n    materialType = sgExtension.getMaterialType()\n    pending.push(sgExtension.extendParams(materialParams, materialDef, parser))\n  } else if (materialExtensions[EXTENSIONS.KHR_MATERIALS_UNLIT]) {\n    var kmuExtension = extensions[EXTENSIONS.KHR_MATERIALS_UNLIT]\n    materialType = kmuExtension.getMaterialType()\n    pending.push(kmuExtension.extendParams(materialParams, materialDef, parser))\n  } else {\n    // Specification:\n    // https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#metallic-roughness-material\n\n    var metallicRoughness = materialDef.pbrMetallicRoughness || {}\n\n    materialParams.color = new THREE.Color(1.0, 1.0, 1.0)\n    materialParams.opacity = 1.0\n\n    if (Array.isArray(metallicRoughness.baseColorFactor)) {\n      var array = metallicRoughness.baseColorFactor\n\n      materialParams.color.fromArray(array)\n      materialParams.opacity = array[3]\n    }\n\n    materialParams.metalness = metallicRoughness.metallicFactor !== undefined ? metallicRoughness.metallicFactor : 1.0\n    materialParams.roughness = metallicRoughness.roughnessFactor !== undefined ? metallicRoughness.roughnessFactor : 1.0\n\n    materialType = this._invokeOne(function (ext) {\n      return ext.getMaterialType && ext.getMaterialType(materialIndex)\n    })\n\n    pending.push(\n      Promise.all(\n        this._invokeAll(function (ext) {\n          return ext.extendMaterialParams && ext.extendMaterialParams(materialIndex, materialParams)\n        })\n      )\n    )\n  }\n\n  if (materialDef.doubleSided === true) {\n    materialParams.side = THREE.DoubleSide\n  }\n\n  var alphaMode = materialDef.alphaMode || ALPHA_MODES.OPAQUE\n\n  if (alphaMode === ALPHA_MODES.BLEND) {\n    materialParams.transparent = true\n\n    // See: https://github.com/mrdoob/three.js/issues/17706\n    materialParams.depthWrite = false\n  } else {\n    materialParams.transparent = false\n\n    if (alphaMode === ALPHA_MODES.MASK) {\n      materialParams.alphaTest = materialDef.alphaCutoff !== undefined ? materialDef.alphaCutoff : 0.5\n    }\n  }\n\n  if (materialDef.normalTexture !== undefined && materialType !== THREE.MeshBasicMaterial) {\n    materialParams.normalScale = new THREE.Vector2(1, 1)\n\n    if (materialDef.normalTexture.scale !== undefined) {\n      materialParams.normalScale.set(materialDef.normalTexture.scale, materialDef.normalTexture.scale)\n    }\n  }\n\n  if (materialDef.occlusionTexture !== undefined && materialType !== THREE.MeshBasicMaterial) {\n    if (materialDef.occlusionTexture.strength !== undefined) {\n      materialParams.aoMapIntensity = materialDef.occlusionTexture.strength\n    }\n  }\n\n  if (materialDef.emissiveFactor !== undefined && materialType !== THREE.MeshBasicMaterial) {\n    materialParams.emissive = new THREE.Color().fromArray(materialDef.emissiveFactor)\n  }\n\n  return Promise.all(pending).then(function () {\n    var material\n\n    material = new materialType(materialParams)\n\n    if (materialDef.name) material.name = materialDef.name\n\n    // baseColorTexture, emissiveTexture, and specularGlossinessTexture use sRGB encoding.\n    if (material.map) material.map.encoding = THREE.sRGBEncoding\n    if (material.emissiveMap) material.emissiveMap.encoding = THREE.sRGBEncoding\n\n    assignExtrasToUserData(material, materialDef)\n\n    parser.associations.set(material, { type: 'materials', index: materialIndex })\n\n    if (materialDef.extensions) addUnknownExtensionsToUserData(extensions, material, materialDef)\n\n    return material\n  })\n}\n\n/** When Object3D instances are targeted by animation, they need unique names. */\nGLTFParser.prototype.createUniqueName = function (originalName) {\n  var sanitizedName = THREE.PropertyBinding.sanitizeNodeName(originalName || '')\n\n  var name = sanitizedName\n\n  for (var i = 1; this.nodeNamesUsed[name]; ++i) {\n    name = sanitizedName + '_' + i\n  }\n\n  this.nodeNamesUsed[name] = true\n\n  return name\n}\n\n/**\n * @param {THREE.BufferGeometry} geometry\n * @param {GLTF.Primitive} primitiveDef\n * @param {GLTFParser} parser\n */\nfunction computeBounds(geometry, primitiveDef, parser) {\n  var attributes = primitiveDef.attributes\n\n  var box = new THREE.Box3()\n\n  if (attributes.POSITION !== undefined) {\n    var accessor = parser.json.accessors[attributes.POSITION]\n\n    var min = accessor.min\n    var max = accessor.max\n\n    // glTF requires 'min' and 'max', but VRM (which extends glTF) currently ignores that requirement.\n\n    if (min !== undefined && max !== undefined) {\n      box.set(new THREE.Vector3(min[0], min[1], min[2]), new THREE.Vector3(max[0], max[1], max[2]))\n    } else {\n      console.warn('THREE.GLTFLoader: Missing min/max properties for accessor POSITION.')\n\n      return\n    }\n  } else {\n    return\n  }\n\n  var targets = primitiveDef.targets\n\n  if (targets !== undefined) {\n    var maxDisplacement = new THREE.Vector3()\n    var vector = new THREE.Vector3()\n\n    for (var i = 0, il = targets.length; i < il; i++) {\n      var target = targets[i]\n\n      if (target.POSITION !== undefined) {\n        var accessor = parser.json.accessors[target.POSITION]\n        var min = accessor.min\n        var max = accessor.max\n\n        // glTF requires 'min' and 'max', but VRM (which extends glTF) currently ignores that requirement.\n\n        if (min !== undefined && max !== undefined) {\n          // we need to get max of absolute components because target weight is [-1,1]\n          vector.setX(Math.max(Math.abs(min[0]), Math.abs(max[0])))\n          vector.setY(Math.max(Math.abs(min[1]), Math.abs(max[1])))\n          vector.setZ(Math.max(Math.abs(min[2]), Math.abs(max[2])))\n\n          // Note: this assumes that the sum of all weights is at most 1. This isn't quite correct - it's more conservative\n          // to assume that each target can have a max weight of 1. However, for some use cases - notably, when morph targets\n          // are used to implement key-frame animations and as such only two are active at a time - this results in very large\n          // boxes. So for now we make a box that's sometimes a touch too small but is hopefully mostly of reasonable size.\n          maxDisplacement.max(vector)\n        } else {\n          console.warn('THREE.GLTFLoader: Missing min/max properties for accessor POSITION.')\n        }\n      }\n    }\n\n    // As per comment above this box isn't conservative, but has a reasonable size for a very large number of morph targets.\n    box.expandByVector(maxDisplacement)\n  }\n\n  geometry.boundingBox = box\n\n  var sphere = new THREE.Sphere()\n\n  box.getCenter(sphere.center)\n  sphere.radius = box.min.distanceTo(box.max) / 2\n\n  geometry.boundingSphere = sphere\n}\n\n/**\n * @param {THREE.BufferGeometry} geometry\n * @param {GLTF.Primitive} primitiveDef\n * @param {GLTFParser} parser\n * @return {Promise<THREE.BufferGeometry>}\n */\nfunction addPrimitiveAttributes(geometry, primitiveDef, parser) {\n  var attributes = primitiveDef.attributes\n\n  var pending = []\n\n  function assignAttributeAccessor(accessorIndex, attributeName) {\n    return parser.getDependency('accessor', accessorIndex).then(function (accessor) {\n      geometry.setAttribute(attributeName, accessor)\n    })\n  }\n\n  for (var gltfAttributeName in attributes) {\n    var threeAttributeName = ATTRIBUTES[gltfAttributeName] || gltfAttributeName.toLowerCase()\n\n    // Skip attributes already provided by e.g. Draco extension.\n    if (threeAttributeName in geometry.attributes) continue\n\n    pending.push(assignAttributeAccessor(attributes[gltfAttributeName], threeAttributeName))\n  }\n\n  if (primitiveDef.indices !== undefined && !geometry.index) {\n    var accessor = parser.getDependency('accessor', primitiveDef.indices).then(function (accessor) {\n      geometry.setIndex(accessor)\n    })\n\n    pending.push(accessor)\n  }\n\n  assignExtrasToUserData(geometry, primitiveDef)\n\n  computeBounds(geometry, primitiveDef, parser)\n\n  return Promise.all(pending).then(function () {\n    return primitiveDef.targets !== undefined ? addMorphTargets(geometry, primitiveDef.targets, parser) : geometry\n  })\n}\n\n/**\n * @param {THREE.BufferGeometry} geometry\n * @param {Number} drawMode\n * @return {THREE.BufferGeometry}\n */\nfunction toTrianglesDrawMode(geometry, drawMode) {\n  var index = geometry.getIndex()\n\n  // generate index if not present\n\n  if (index === null) {\n    var indices = []\n\n    var position = geometry.getAttribute('position')\n\n    if (position !== undefined) {\n      for (var i = 0; i < position.count; i++) {\n        indices.push(i)\n      }\n\n      geometry.setIndex(indices)\n      index = geometry.getIndex()\n    } else {\n      console.error('THREE.GLTFLoader.toTrianglesDrawMode(): Undefined position attribute. Processing not possible.')\n      return geometry\n    }\n  }\n\n  //\n\n  var numberOfTriangles = index.count - 2\n  var newIndices = []\n\n  if (drawMode === THREE.TriangleFanDrawMode) {\n    // gl.TRIANGLE_FAN\n\n    for (var i = 1; i <= numberOfTriangles; i++) {\n      newIndices.push(index.getX(0))\n      newIndices.push(index.getX(i))\n      newIndices.push(index.getX(i + 1))\n    }\n  } else {\n    // gl.TRIANGLE_STRIP\n\n    for (var i = 0; i < numberOfTriangles; i++) {\n      if (i % 2 === 0) {\n        newIndices.push(index.getX(i))\n        newIndices.push(index.getX(i + 1))\n        newIndices.push(index.getX(i + 2))\n      } else {\n        newIndices.push(index.getX(i + 2))\n        newIndices.push(index.getX(i + 1))\n        newIndices.push(index.getX(i))\n      }\n    }\n  }\n\n  if (newIndices.length / 3 !== numberOfTriangles) {\n    console.error('THREE.GLTFLoader.toTrianglesDrawMode(): Unable to generate correct amount of triangles.')\n  }\n\n  // build final geometry\n\n  var newGeometry = geometry.clone()\n  newGeometry.setIndex(newIndices)\n\n  return newGeometry\n}\n\n/**\n * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#geometry\n *\n * Creates BufferGeometries from primitives.\n *\n * @param {Array<GLTF.Primitive>} primitives\n * @return {Promise<Array<THREE.BufferGeometry>>}\n */\nGLTFParser.prototype.loadGeometries = function (primitives) {\n  var parser = this\n  var extensions = this.extensions\n  var cache = this.primitiveCache\n\n  function createDracoPrimitive(primitive) {\n    return extensions[EXTENSIONS.KHR_DRACO_MESH_COMPRESSION]\n      .decodePrimitive(primitive, parser)\n      .then(function (geometry) {\n        return addPrimitiveAttributes(geometry, primitive, parser)\n      })\n  }\n\n  var pending = []\n\n  for (var i = 0, il = primitives.length; i < il; i++) {\n    var primitive = primitives[i]\n    var cacheKey = createPrimitiveKey(primitive)\n\n    // See if we've already created this geometry\n    var cached = cache[cacheKey]\n\n    if (cached) {\n      // Use the cached geometry if it exists\n      pending.push(cached.promise)\n    } else {\n      var geometryPromise\n\n      if (primitive.extensions && primitive.extensions[EXTENSIONS.KHR_DRACO_MESH_COMPRESSION]) {\n        // Use DRACO geometry if available\n        geometryPromise = createDracoPrimitive(primitive)\n      } else {\n        // Otherwise create a new geometry\n        geometryPromise = addPrimitiveAttributes(new THREE.BufferGeometry(), primitive, parser)\n      }\n\n      // Cache this geometry\n      cache[cacheKey] = { primitive: primitive, promise: geometryPromise }\n\n      pending.push(geometryPromise)\n    }\n  }\n\n  return Promise.all(pending)\n}\n\n/**\n * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#meshes\n * @param {number} meshIndex\n * @return {Promise<THREE.Group|THREE.Mesh|THREE.SkinnedMesh>}\n */\nGLTFParser.prototype.loadMesh = function (meshIndex) {\n  var parser = this\n  var json = this.json\n  var extensions = this.extensions\n\n  var meshDef = json.meshes[meshIndex]\n  var primitives = meshDef.primitives\n\n  var pending = []\n\n  for (var i = 0, il = primitives.length; i < il; i++) {\n    var material =\n      primitives[i].material === undefined\n        ? createDefaultMaterial(this.cache)\n        : this.getDependency('material', primitives[i].material)\n\n    pending.push(material)\n  }\n\n  pending.push(parser.loadGeometries(primitives))\n\n  return Promise.all(pending).then(function (results) {\n    var materials = results.slice(0, results.length - 1)\n    var geometries = results[results.length - 1]\n\n    var meshes = []\n\n    for (var i = 0, il = geometries.length; i < il; i++) {\n      var geometry = geometries[i]\n      var primitive = primitives[i]\n\n      // 1. create Mesh\n      var mesh\n      var material = materials[i]\n\n      if (\n        primitive.mode === WEBGL_CONSTANTS.TRIANGLES ||\n        primitive.mode === WEBGL_CONSTANTS.TRIANGLE_STRIP ||\n        primitive.mode === WEBGL_CONSTANTS.TRIANGLE_FAN ||\n        primitive.mode === undefined\n      ) {\n        // .isSkinnedMesh isn't in glTF spec. See ._markDefs()\n        if (geometry.morphAttributes && Object.keys(geometry.morphAttributes).length > 0) {\n          meshDef.hasMorphAttributes = true\n        }\n        geometry.morphAttributes = {}\n        mesh =\n          meshDef.isSkinnedMesh === true\n            ? new THREE.SkinnedMesh(geometry, material)\n            : new THREE.Mesh(geometry, material)\n\n        if (primitive.mode === WEBGL_CONSTANTS.TRIANGLE_STRIP) {\n          mesh.geometry = toTrianglesDrawMode(mesh.geometry, THREE.TriangleStripDrawMode)\n        } else if (primitive.mode === WEBGL_CONSTANTS.TRIANGLE_FAN) {\n          mesh.geometry = toTrianglesDrawMode(mesh.geometry, THREE.TriangleFanDrawMode)\n        }\n      } else if (primitive.mode === WEBGL_CONSTANTS.LINES) {\n        mesh = new THREE.LineSegments(geometry, material)\n      } else if (primitive.mode === WEBGL_CONSTANTS.LINE_STRIP) {\n        mesh = new THREE.Line(geometry, material)\n      } else if (primitive.mode === WEBGL_CONSTANTS.LINE_LOOP) {\n        mesh = new THREE.LineLoop(geometry, material)\n      } else if (primitive.mode === WEBGL_CONSTANTS.POINTS) {\n        mesh = new THREE.Points(geometry, material)\n      } else {\n        throw new Error('THREE.GLTFLoader: Primitive mode unsupported: ' + primitive.mode)\n      }\n\n      if (meshDef.hasMorphAttributes)  {\n        // Just flag the mesh, so that parser.js can link morphTarget dictionaries and influences\n        // This prevented a crash relating to morphTarget definitions\n        mesh.morphTargetDictionary = true\n        mesh.morphTargetInfluences = true\n      }\n\n      mesh.name = parser.createUniqueName(meshDef.name || 'mesh_' + meshIndex)\n\n      assignExtrasToUserData(mesh, meshDef)\n      if (primitive.extensions) addUnknownExtensionsToUserData(extensions, mesh, primitive)\n\n      parser.assignFinalMaterial(mesh)\n\n      meshes.push(mesh)\n    }\n\n    if (meshes.length === 1) {\n      return meshes[0]\n    }\n\n    var group = new THREE.Group()\n\n    for (var i = 0, il = meshes.length; i < il; i++) {\n      group.add(meshes[i])\n    }\n\n    return group\n  })\n}\n\n/**\n * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#cameras\n * @param {number} cameraIndex\n * @return {Promise<THREE.Camera>}\n */\nGLTFParser.prototype.loadCamera = function (cameraIndex) {\n  var camera\n  var cameraDef = this.json.cameras[cameraIndex]\n  var params = cameraDef[cameraDef.type]\n\n  if (!params) {\n    console.warn('THREE.GLTFLoader: Missing camera parameters.')\n    return\n  }\n\n  if (cameraDef.type === 'perspective') {\n    camera = new THREE.PerspectiveCamera(\n      THREE.MathUtils.radToDeg(params.yfov),\n      params.aspectRatio || 1,\n      params.znear || 1,\n      params.zfar || 2e6\n    )\n  } else if (cameraDef.type === 'orthographic') {\n    camera = new THREE.OrthographicCamera(\n      -params.xmag,\n      params.xmag,\n      params.ymag,\n      -params.ymag,\n      params.znear,\n      params.zfar\n    )\n  }\n\n  if (cameraDef.name) camera.name = this.createUniqueName(cameraDef.name)\n\n  assignExtrasToUserData(camera, cameraDef)\n\n  return Promise.resolve(camera)\n}\n\n/**\n * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#skins\n * @param {number} skinIndex\n * @return {Promise<Object>}\n */\nGLTFParser.prototype.loadSkin = function (skinIndex) {\n  var skinDef = this.json.skins[skinIndex]\n\n  var skinEntry = { joints: skinDef.joints }\n\n  if (skinDef.inverseBindMatrices === undefined) {\n    return Promise.resolve(skinEntry)\n  }\n\n  return this.getDependency('accessor', skinDef.inverseBindMatrices).then(function (accessor) {\n    skinEntry.inverseBindMatrices = accessor\n\n    return skinEntry\n  })\n}\n\n/**\n * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#animations\n * @param {number} animationIndex\n * @return {Promise<THREE.AnimationClip>}\n */\nGLTFParser.prototype.loadAnimation = function (animationIndex) {\n  var json = this.json\n\n  var animationDef = json.animations[animationIndex]\n\n  var pendingNodes = []\n  var pendingInputAccessors = []\n  var pendingOutputAccessors = []\n  var pendingSamplers = []\n  var pendingTargets = []\n\n  for (var i = 0, il = animationDef.channels.length; i < il; i++) {\n    var channel = animationDef.channels[i]\n    var sampler = animationDef.samplers[channel.sampler]\n    var target = channel.target\n    var name = target.node !== undefined ? target.node : target.id // NOTE: target.id is deprecated.\n    var input = animationDef.parameters !== undefined ? animationDef.parameters[sampler.input] : sampler.input\n    var output = animationDef.parameters !== undefined ? animationDef.parameters[sampler.output] : sampler.output\n\n    pendingNodes.push(this.getDependency('node', name))\n    pendingInputAccessors.push(this.getDependency('accessor', input))\n    pendingOutputAccessors.push(this.getDependency('accessor', output))\n    pendingSamplers.push(sampler)\n    pendingTargets.push(target)\n  }\n\n  return Promise.all([\n    Promise.all(pendingNodes),\n    Promise.all(pendingInputAccessors),\n    Promise.all(pendingOutputAccessors),\n    Promise.all(pendingSamplers),\n    Promise.all(pendingTargets),\n  ]).then(function (dependencies) {\n    var nodes = dependencies[0]\n    var inputAccessors = dependencies[1]\n    var outputAccessors = dependencies[2]\n    var samplers = dependencies[3]\n    var targets = dependencies[4]\n\n    var tracks = []\n\n    for (var i = 0, il = nodes.length; i < il; i++) {\n      var node = nodes[i]\n      var inputAccessor = inputAccessors[i]\n      var outputAccessor = outputAccessors[i]\n      var sampler = samplers[i]\n      var target = targets[i]\n\n      if (node === undefined) continue\n\n      node.updateMatrix()\n      node.matrixAutoUpdate = true\n\n      var TypedKeyframeTrack\n\n      switch (PATH_PROPERTIES[target.path]) {\n        case PATH_PROPERTIES.weights:\n          TypedKeyframeTrack = THREE.NumberKeyframeTrack\n          break\n\n        case PATH_PROPERTIES.rotation:\n          TypedKeyframeTrack = THREE.QuaternionKeyframeTrack\n          break\n\n        case PATH_PROPERTIES.position:\n        case PATH_PROPERTIES.scale:\n        default:\n          TypedKeyframeTrack = THREE.VectorKeyframeTrack\n          break\n      }\n\n      var targetName = node.name ? node.name : node.uuid\n\n      var interpolation =\n        sampler.interpolation !== undefined ? INTERPOLATION[sampler.interpolation] : THREE.InterpolateLinear\n\n      var targetNames = []\n\n      if (PATH_PROPERTIES[target.path] === PATH_PROPERTIES.weights) {\n        // Node may be a THREE.Group (glTF mesh with several primitives) or a THREE.Mesh.\n        node.traverse(function (object) {\n          if (object.isMesh === true && object.morphTargetInfluences) {\n            targetNames.push(object.name ? object.name : object.uuid)\n          }\n        })\n      } else {\n        targetNames.push(targetName)\n      }\n\n      if (outputAccessor === null) continue\n      var outputArray = outputAccessor.array\n\n      if (outputAccessor.normalized) {\n        var scale\n\n        if (outputArray.constructor === Int8Array) {\n          scale = 1 / 127\n        } else if (outputArray.constructor === Uint8Array) {\n          scale = 1 / 255\n        } else if (outputArray.constructor == Int16Array) {\n          scale = 1 / 32767\n        } else if (outputArray.constructor === Uint16Array) {\n          scale = 1 / 65535\n        } else {\n          throw new Error('THREE.GLTFLoader: Unsupported output accessor component type.')\n        }\n\n        var scaled = new Float32Array(outputArray.length)\n\n        for (var j = 0, jl = outputArray.length; j < jl; j++) {\n          scaled[j] = outputArray[j] * scale\n        }\n\n        outputArray = scaled\n      }\n    }\n\n    var name = animationDef.name ? animationDef.name : 'animation_' + animationIndex\n    var clip = new THREE.AnimationClip(name, undefined, tracks)\n    clip.targetNames = targetNames\n    return clip\n  })\n}\n\nGLTFParser.prototype.createNodeMesh = function (nodeIndex) {\n  const json = this.json\n  const parser = this\n  const nodeDef = json.nodes[nodeIndex]\n\n  if (nodeDef.mesh === undefined) return null\n\n  return parser.getDependency('mesh', nodeDef.mesh).then(function (mesh) {\n    const node = parser._getNodeRef(parser.meshCache, nodeDef.mesh, mesh)\n\n    // if weights are provided on the node, override weights on the mesh.\n    if (nodeDef.weights !== undefined) {\n      node.traverse(function (o) {\n        if (!o.isMesh) return\n\n        for (let i = 0, il = nodeDef.weights.length; i < il; i++) {\n          o.morphTargetInfluences[i] = nodeDef.weights[i]\n        }\n      })\n    }\n\n    return node\n  })\n}\n\n/**\n * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#nodes-and-hierarchy\n * @param {number} nodeIndex\n * @return {Promise<THREE.Object3D>}\n */\nGLTFParser.prototype.loadNode = function (nodeIndex) {\n  var json = this.json\n  var extensions = this.extensions\n  var parser = this\n\n  var nodeDef = json.nodes[nodeIndex]\n\n  // reserve node's name before its dependencies, so the root has the intended name.\n  var nodeName = nodeDef.name ? parser.createUniqueName(nodeDef.name) : ''\n\n  return (function () {\n    var pending = []\n\n    const meshPromise = parser._invokeOne(function (ext) {\n      return ext.createNodeMesh && ext.createNodeMesh(nodeIndex)\n    })\n\n    if (meshPromise) {\n      pending.push(meshPromise)\n    }\n\n    if (nodeDef.camera !== undefined) {\n      pending.push(\n        parser.getDependency('camera', nodeDef.camera).then(function (camera) {\n          return parser._getNodeRef(parser.cameraCache, nodeDef.camera, camera)\n        })\n      )\n    }\n\n    parser\n      ._invokeAll(function (ext) {\n        return ext.createNodeAttachment && ext.createNodeAttachment(nodeIndex)\n      })\n      .forEach(function (promise) {\n        pending.push(promise)\n      })\n\n    return Promise.all(pending)\n  })().then(function (objects) {\n    var node\n\n    // .isBone isn't in glTF spec. See ._markDefs\n    if (nodeDef.isBone === true) {\n      node = new THREE.Bone()\n    } else if (objects.length > 1) {\n      node = new THREE.Group()\n    } else if (objects.length === 1) {\n      node = objects[0]\n    } else {\n      node = new THREE.Object3D()\n    }\n\n    if (node !== objects[0]) {\n      for (var i = 0, il = objects.length; i < il; i++) {\n        node.add(objects[i])\n      }\n    }\n\n    if (nodeDef.name) {\n      node.userData.name = nodeDef.name\n      node.name = nodeName\n    }\n\n    assignExtrasToUserData(node, nodeDef)\n\n    if (nodeDef.extensions) addUnknownExtensionsToUserData(extensions, node, nodeDef)\n\n    if (nodeDef.matrix !== undefined) {\n      var matrix = new THREE.Matrix4()\n      matrix.fromArray(nodeDef.matrix)\n      node.applyMatrix4(matrix)\n    } else {\n      if (nodeDef.translation !== undefined) {\n        node.position.fromArray(nodeDef.translation)\n      }\n\n      if (nodeDef.rotation !== undefined) {\n        node.quaternion.fromArray(nodeDef.rotation)\n      }\n\n      if (nodeDef.scale !== undefined) {\n        node.scale.fromArray(nodeDef.scale)\n      }\n    }\n\n    parser.associations.set(node, { type: 'nodes', index: nodeIndex })\n\n    return node\n  })\n}\n\n/**\n * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#scenes\n * @param {number} sceneIndex\n * @return {Promise<THREE.Group>}\n */\nGLTFParser.prototype.loadScene = (function () {\n  // scene node hierachy builder\n\n  function buildNodeHierachy(nodeId, parentObject, json, parser) {\n    var nodeDef = json.nodes[nodeId]\n\n    return parser\n      .getDependency('node', nodeId)\n      .then(function (node) {\n        if (nodeDef.skin === undefined) return node\n\n        // build skeleton here as well\n\n        var skinEntry\n\n        return parser\n          .getDependency('skin', nodeDef.skin)\n          .then(function (skin) {\n            skinEntry = skin\n\n            var pendingJoints = []\n\n            for (var i = 0, il = skinEntry.joints.length; i < il; i++) {\n              pendingJoints.push(parser.getDependency('node', skinEntry.joints[i]))\n            }\n\n            return Promise.all(pendingJoints)\n          })\n          .then(function (jointNodes) {\n            node.traverse(function (mesh) {\n              if (!mesh.isMesh) return\n\n              var bones = []\n              var boneInverses = []\n\n              for (var j = 0, jl = jointNodes.length; j < jl; j++) {\n                var jointNode = jointNodes[j]\n\n                if (jointNode) {\n                  bones.push(jointNode)\n\n                  var mat = new THREE.Matrix4()\n\n                  if (skinEntry.inverseBindMatrices !== undefined) {\n                    mat.fromArray(skinEntry.inverseBindMatrices.array, j * 16)\n                  }\n\n                  boneInverses.push(mat)\n                } else {\n                  console.warn('THREE.GLTFLoader: Joint \"%s\" could not be found.', skinEntry.joints[j])\n                }\n              }\n\n              mesh.bind(new THREE.Skeleton(bones, boneInverses), mesh.matrixWorld)\n            })\n\n            return node\n          })\n      })\n      .then(function (node) {\n        // build node hierachy\n\n        parentObject.add(node)\n\n        var pending = []\n\n        if (nodeDef.children) {\n          var children = nodeDef.children\n\n          for (var i = 0, il = children.length; i < il; i++) {\n            var child = children[i]\n            pending.push(buildNodeHierachy(child, node, json, parser))\n          }\n        }\n\n        return Promise.all(pending)\n      })\n  }\n\n  return function loadScene(sceneIndex) {\n    var json = this.json\n    var extensions = this.extensions\n    var sceneDef = this.json.scenes[sceneIndex]\n    var parser = this\n\n    // Loader returns Group, not Scene.\n    // See: https://github.com/mrdoob/three.js/issues/18342#issuecomment-578981172\n    var scene = new THREE.Group()\n    if (sceneDef.name) scene.name = parser.createUniqueName(sceneDef.name)\n\n    assignExtrasToUserData(scene, sceneDef)\n\n    if (sceneDef.extensions) addUnknownExtensionsToUserData(extensions, scene, sceneDef)\n\n    var nodeIds = sceneDef.nodes || []\n\n    var pending = []\n\n    for (var i = 0, il = nodeIds.length; i < il; i++) {\n      pending.push(buildNodeHierachy(nodeIds[i], scene, json, parser))\n    }\n\n    return Promise.all(pending).then(function () {\n      return scene\n    })\n  }\n})()\n"
  },
  {
    "path": "src/gltfjsx.js",
    "content": "import 'jsdom-global'\nimport fs from 'fs'\nimport path from 'path'\nimport transform from './utils/transform.js'\n\nimport { GLTFLoader } from './bin/GLTFLoader.js'\nimport { DRACOLoader } from './bin/DRACOLoader.js'\nDRACOLoader.getDecoderModule = () => {}\nimport parse from './utils/parser.js'\n\nconst gltfLoader = new GLTFLoader()\ngltfLoader.setDRACOLoader(new DRACOLoader())\n\nfunction toArrayBuffer(buf) {\n  var ab = new ArrayBuffer(buf.length)\n  var view = new Uint8Array(ab)\n  for (var i = 0; i < buf.length; ++i) view[i] = buf[i]\n  return ab\n}\n\nfunction roundOff(value) {\n  return Math.round(value * 100) / 100\n}\n\nfunction getFileSize(file) {\n  const stats = fs.statSync(file)\n  let fileSize = stats.size\n  let fileSizeKB = roundOff(fileSize * 0.001)\n  let fileSizeMB = roundOff(fileSizeKB * 0.001)\n  return {\n    size: fileSizeKB > 1000 ? `${fileSizeMB}MB` : `${fileSizeKB}KB`,\n    sizeKB: fileSizeKB,\n  }\n}\n\nexport default function (file, output, options) {\n  function getRelativeFilePath(file) {\n    const filePath = path.resolve(file)\n    const rootPath = options.root ? path.resolve(options.root) : path.dirname(file)\n    const relativePath = path.relative(rootPath, filePath) || ''\n    if (process.platform === 'win32') return relativePath.replace(/\\\\/g, '/')\n    return relativePath\n  }\n\n  return new Promise((resolve, reject) => {\n    async function run(stream) {\n      let size = ''\n      // Process GLTF\n      if (output && path.parse(output).ext === '.tsx') options.types = true\n      if (options.transform || options.instance || options.instanceall) {\n        const { name } = path.parse(file)\n        const outputDir = path.parse(path.resolve(output ?? file)).dir\n        const transformOut = path.join(outputDir, name + '-transformed.glb')\n        await transform(file, transformOut, options)\n        const { size: sizeOriginal, sizeKB: sizeKBOriginal } = getFileSize(file)\n        const { size: sizeTransformed, sizeKB: sizeKBTransformed } = getFileSize(transformOut)\n        size = `${file} [${sizeOriginal}] > ${transformOut} [${sizeTransformed}] (${Math.round(\n          100 - (sizeKBTransformed / sizeKBOriginal) * 100\n        )}%)`\n        file = transformOut\n      }\n      const filePath = getRelativeFilePath(file)\n      const data = fs.readFileSync(file)\n      const arrayBuffer = toArrayBuffer(data)\n      gltfLoader.parse(\n        arrayBuffer,\n        '',\n        async (gltf) => {\n          const output = await parse(gltf, { fileName: filePath, size, ...options })\n          if (options.console) console.log(output)\n          else stream?.write(output)\n          stream?.end()\n          resolve()\n        },\n        (reason) => console.log(reason)\n      )\n    }\n\n    if (options.console) {\n      run()\n    } else {\n      const stream = fs.createWriteStream(path.resolve(output))\n      stream.once('open', async () => {\n        if (!fs.existsSync(file)) reject(file + ' does not exist.')\n        else run(stream)\n      })\n    }\n  })\n}\n"
  },
  {
    "path": "src/test.js",
    "content": "import assert from 'node:assert'\nconst cli = await import('../cli.js')\n\nassert(cli)\n"
  },
  {
    "path": "src/utils/exports.js",
    "content": "import parse from './parser.js'\nimport { GLTFLoader as GLTFStructureLoader } from '../bin/GLTFLoader.js'\n\nexport { parse, GLTFStructureLoader }\n"
  },
  {
    "path": "src/utils/isVarName.js",
    "content": "const isVarName = (str) => {\n  // eslint-disable-next-line no-misleading-character-class\n  const regex = new RegExp(\n    // eslint-disable-next-line no-misleading-character-class\n    /^(?!(?:do|if|in|for|let|new|try|var|case|else|enum|eval|null|this|true|void|with|await|break|catch|class|const|false|super|throw|while|yield|delete|export|import|public|return|static|switch|typeof|default|extends|finally|package|private|continue|debugger|function|arguments|interface|protected|implements|instanceof)$)(?:[$A-Z_a-z\\xAA\\xB5\\xBA\\xC0-\\xD6\\xD8-\\xF6\\xF8-\\u02C1\\u02C6-\\u02D1\\u02E0-\\u02E4\\u02EC\\u02EE\\u0370-\\u0374\\u0376\\u0377\\u037A-\\u037D\\u037F\\u0386\\u0388-\\u038A\\u038C\\u038E-\\u03A1\\u03A3-\\u03F5\\u03F7-\\u0481\\u048A-\\u052F\\u0531-\\u0556\\u0559\\u0560-\\u0588\\u05D0-\\u05EA\\u05EF-\\u05F2\\u0620-\\u064A\\u066E\\u066F\\u0671-\\u06D3\\u06D5\\u06E5\\u06E6\\u06EE\\u06EF\\u06FA-\\u06FC\\u06FF\\u0710\\u0712-\\u072F\\u074D-\\u07A5\\u07B1\\u07CA-\\u07EA\\u07F4\\u07F5\\u07FA\\u0800-\\u0815\\u081A\\u0824\\u0828\\u0840-\\u0858\\u0860-\\u086A\\u08A0-\\u08B4\\u08B6-\\u08BD\\u0904-\\u0939\\u093D\\u0950\\u0958-\\u0961\\u0971-\\u0980\\u0985-\\u098C\\u098F\\u0990\\u0993-\\u09A8\\u09AA-\\u09B0\\u09B2\\u09B6-\\u09B9\\u09BD\\u09CE\\u09DC\\u09DD\\u09DF-\\u09E1\\u09F0\\u09F1\\u09FC\\u0A05-\\u0A0A\\u0A0F\\u0A10\\u0A13-\\u0A28\\u0A2A-\\u0A30\\u0A32\\u0A33\\u0A35\\u0A36\\u0A38\\u0A39\\u0A59-\\u0A5C\\u0A5E\\u0A72-\\u0A74\\u0A85-\\u0A8D\\u0A8F-\\u0A91\\u0A93-\\u0AA8\\u0AAA-\\u0AB0\\u0AB2\\u0AB3\\u0AB5-\\u0AB9\\u0ABD\\u0AD0\\u0AE0\\u0AE1\\u0AF9\\u0B05-\\u0B0C\\u0B0F\\u0B10\\u0B13-\\u0B28\\u0B2A-\\u0B30\\u0B32\\u0B33\\u0B35-\\u0B39\\u0B3D\\u0B5C\\u0B5D\\u0B5F-\\u0B61\\u0B71\\u0B83\\u0B85-\\u0B8A\\u0B8E-\\u0B90\\u0B92-\\u0B95\\u0B99\\u0B9A\\u0B9C\\u0B9E\\u0B9F\\u0BA3\\u0BA4\\u0BA8-\\u0BAA\\u0BAE-\\u0BB9\\u0BD0\\u0C05-\\u0C0C\\u0C0E-\\u0C10\\u0C12-\\u0C28\\u0C2A-\\u0C39\\u0C3D\\u0C58-\\u0C5A\\u0C60\\u0C61\\u0C80\\u0C85-\\u0C8C\\u0C8E-\\u0C90\\u0C92-\\u0CA8\\u0CAA-\\u0CB3\\u0CB5-\\u0CB9\\u0CBD\\u0CDE\\u0CE0\\u0CE1\\u0CF1\\u0CF2\\u0D05-\\u0D0C\\u0D0E-\\u0D10\\u0D12-\\u0D3A\\u0D3D\\u0D4E\\u0D54-\\u0D56\\u0D5F-\\u0D61\\u0D7A-\\u0D7F\\u0D85-\\u0D96\\u0D9A-\\u0DB1\\u0DB3-\\u0DBB\\u0DBD\\u0DC0-\\u0DC6\\u0E01-\\u0E30\\u0E32\\u0E33\\u0E40-\\u0E46\\u0E81\\u0E82\\u0E84\\u0E87\\u0E88\\u0E8A\\u0E8D\\u0E94-\\u0E97\\u0E99-\\u0E9F\\u0EA1-\\u0EA3\\u0EA5\\u0EA7\\u0EAA\\u0EAB\\u0EAD-\\u0EB0\\u0EB2\\u0EB3\\u0EBD\\u0EC0-\\u0EC4\\u0EC6\\u0EDC-\\u0EDF\\u0F00\\u0F40-\\u0F47\\u0F49-\\u0F6C\\u0F88-\\u0F8C\\u1000-\\u102A\\u103F\\u1050-\\u1055\\u105A-\\u105D\\u1061\\u1065\\u1066\\u106E-\\u1070\\u1075-\\u1081\\u108E\\u10A0-\\u10C5\\u10C7\\u10CD\\u10D0-\\u10FA\\u10FC-\\u1248\\u124A-\\u124D\\u1250-\\u1256\\u1258\\u125A-\\u125D\\u1260-\\u1288\\u128A-\\u128D\\u1290-\\u12B0\\u12B2-\\u12B5\\u12B8-\\u12BE\\u12C0\\u12C2-\\u12C5\\u12C8-\\u12D6\\u12D8-\\u1310\\u1312-\\u1315\\u1318-\\u135A\\u1380-\\u138F\\u13A0-\\u13F5\\u13F8-\\u13FD\\u1401-\\u166C\\u166F-\\u167F\\u1681-\\u169A\\u16A0-\\u16EA\\u16EE-\\u16F8\\u1700-\\u170C\\u170E-\\u1711\\u1720-\\u1731\\u1740-\\u1751\\u1760-\\u176C\\u176E-\\u1770\\u1780-\\u17B3\\u17D7\\u17DC\\u1820-\\u1878\\u1880-\\u18A8\\u18AA\\u18B0-\\u18F5\\u1900-\\u191E\\u1950-\\u196D\\u1970-\\u1974\\u1980-\\u19AB\\u19B0-\\u19C9\\u1A00-\\u1A16\\u1A20-\\u1A54\\u1AA7\\u1B05-\\u1B33\\u1B45-\\u1B4B\\u1B83-\\u1BA0\\u1BAE\\u1BAF\\u1BBA-\\u1BE5\\u1C00-\\u1C23\\u1C4D-\\u1C4F\\u1C5A-\\u1C7D\\u1C80-\\u1C88\\u1C90-\\u1CBA\\u1CBD-\\u1CBF\\u1CE9-\\u1CEC\\u1CEE-\\u1CF1\\u1CF5\\u1CF6\\u1D00-\\u1DBF\\u1E00-\\u1F15\\u1F18-\\u1F1D\\u1F20-\\u1F45\\u1F48-\\u1F4D\\u1F50-\\u1F57\\u1F59\\u1F5B\\u1F5D\\u1F5F-\\u1F7D\\u1F80-\\u1FB4\\u1FB6-\\u1FBC\\u1FBE\\u1FC2-\\u1FC4\\u1FC6-\\u1FCC\\u1FD0-\\u1FD3\\u1FD6-\\u1FDB\\u1FE0-\\u1FEC\\u1FF2-\\u1FF4\\u1FF6-\\u1FFC\\u2071\\u207F\\u2090-\\u209C\\u2102\\u2107\\u210A-\\u2113\\u2115\\u2118-\\u211D\\u2124\\u2126\\u2128\\u212A-\\u2139\\u213C-\\u213F\\u2145-\\u2149\\u214E\\u2160-\\u2188\\u2C00-\\u2C2E\\u2C30-\\u2C5E\\u2C60-\\u2CE4\\u2CEB-\\u2CEE\\u2CF2\\u2CF3\\u2D00-\\u2D25\\u2D27\\u2D2D\\u2D30-\\u2D67\\u2D6F\\u2D80-\\u2D96\\u2DA0-\\u2DA6\\u2DA8-\\u2DAE\\u2DB0-\\u2DB6\\u2DB8-\\u2DBE\\u2DC0-\\u2DC6\\u2DC8-\\u2DCE\\u2DD0-\\u2DD6\\u2DD8-\\u2DDE\\u3005-\\u3007\\u3021-\\u3029\\u3031-\\u3035\\u3038-\\u303C\\u3041-\\u3096\\u309B-\\u309F\\u30A1-\\u30FA\\u30FC-\\u30FF\\u3105-\\u312F\\u3131-\\u318E\\u31A0-\\u31BA\\u31F0-\\u31FF\\u3400-\\u4DB5\\u4E00-\\u9FEF\\uA000-\\uA48C\\uA4D0-\\uA4FD\\uA500-\\uA60C\\uA610-\\uA61F\\uA62A\\uA62B\\uA640-\\uA66E\\uA67F-\\uA69D\\uA6A0-\\uA6EF\\uA717-\\uA71F\\uA722-\\uA788\\uA78B-\\uA7B9\\uA7F7-\\uA801\\uA803-\\uA805\\uA807-\\uA80A\\uA80C-\\uA822\\uA840-\\uA873\\uA882-\\uA8B3\\uA8F2-\\uA8F7\\uA8FB\\uA8FD\\uA8FE\\uA90A-\\uA925\\uA930-\\uA946\\uA960-\\uA97C\\uA984-\\uA9B2\\uA9CF\\uA9E0-\\uA9E4\\uA9E6-\\uA9EF\\uA9FA-\\uA9FE\\uAA00-\\uAA28\\uAA40-\\uAA42\\uAA44-\\uAA4B\\uAA60-\\uAA76\\uAA7A\\uAA7E-\\uAAAF\\uAAB1\\uAAB5\\uAAB6\\uAAB9-\\uAABD\\uAAC0\\uAAC2\\uAADB-\\uAADD\\uAAE0-\\uAAEA\\uAAF2-\\uAAF4\\uAB01-\\uAB06\\uAB09-\\uAB0E\\uAB11-\\uAB16\\uAB20-\\uAB26\\uAB28-\\uAB2E\\uAB30-\\uAB5A\\uAB5C-\\uAB65\\uAB70-\\uABE2\\uAC00-\\uD7A3\\uD7B0-\\uD7C6\\uD7CB-\\uD7FB\\uF900-\\uFA6D\\uFA70-\\uFAD9\\uFB00-\\uFB06\\uFB13-\\uFB17\\uFB1D\\uFB1F-\\uFB28\\uFB2A-\\uFB36\\uFB38-\\uFB3C\\uFB3E\\uFB40\\uFB41\\uFB43\\uFB44\\uFB46-\\uFBB1\\uFBD3-\\uFD3D\\uFD50-\\uFD8F\\uFD92-\\uFDC7\\uFDF0-\\uFDFB\\uFE70-\\uFE74\\uFE76-\\uFEFC\\uFF21-\\uFF3A\\uFF41-\\uFF5A\\uFF66-\\uFFBE\\uFFC2-\\uFFC7\\uFFCA-\\uFFCF\\uFFD2-\\uFFD7\\uFFDA-\\uFFDC]|\\uD800[\\uDC00-\\uDC0B\\uDC0D-\\uDC26\\uDC28-\\uDC3A\\uDC3C\\uDC3D\\uDC3F-\\uDC4D\\uDC50-\\uDC5D\\uDC80-\\uDCFA\\uDD40-\\uDD74\\uDE80-\\uDE9C\\uDEA0-\\uDED0\\uDF00-\\uDF1F\\uDF2D-\\uDF4A\\uDF50-\\uDF75\\uDF80-\\uDF9D\\uDFA0-\\uDFC3\\uDFC8-\\uDFCF\\uDFD1-\\uDFD5]|\\uD801[\\uDC00-\\uDC9D\\uDCB0-\\uDCD3\\uDCD8-\\uDCFB\\uDD00-\\uDD27\\uDD30-\\uDD63\\uDE00-\\uDF36\\uDF40-\\uDF55\\uDF60-\\uDF67]|\\uD802[\\uDC00-\\uDC05\\uDC08\\uDC0A-\\uDC35\\uDC37\\uDC38\\uDC3C\\uDC3F-\\uDC55\\uDC60-\\uDC76\\uDC80-\\uDC9E\\uDCE0-\\uDCF2\\uDCF4\\uDCF5\\uDD00-\\uDD15\\uDD20-\\uDD39\\uDD80-\\uDDB7\\uDDBE\\uDDBF\\uDE00\\uDE10-\\uDE13\\uDE15-\\uDE17\\uDE19-\\uDE35\\uDE60-\\uDE7C\\uDE80-\\uDE9C\\uDEC0-\\uDEC7\\uDEC9-\\uDEE4\\uDF00-\\uDF35\\uDF40-\\uDF55\\uDF60-\\uDF72\\uDF80-\\uDF91]|\\uD803[\\uDC00-\\uDC48\\uDC80-\\uDCB2\\uDCC0-\\uDCF2\\uDD00-\\uDD23\\uDF00-\\uDF1C\\uDF27\\uDF30-\\uDF45]|\\uD804[\\uDC03-\\uDC37\\uDC83-\\uDCAF\\uDCD0-\\uDCE8\\uDD03-\\uDD26\\uDD44\\uDD50-\\uDD72\\uDD76\\uDD83-\\uDDB2\\uDDC1-\\uDDC4\\uDDDA\\uDDDC\\uDE00-\\uDE11\\uDE13-\\uDE2B\\uDE80-\\uDE86\\uDE88\\uDE8A-\\uDE8D\\uDE8F-\\uDE9D\\uDE9F-\\uDEA8\\uDEB0-\\uDEDE\\uDF05-\\uDF0C\\uDF0F\\uDF10\\uDF13-\\uDF28\\uDF2A-\\uDF30\\uDF32\\uDF33\\uDF35-\\uDF39\\uDF3D\\uDF50\\uDF5D-\\uDF61]|\\uD805[\\uDC00-\\uDC34\\uDC47-\\uDC4A\\uDC80-\\uDCAF\\uDCC4\\uDCC5\\uDCC7\\uDD80-\\uDDAE\\uDDD8-\\uDDDB\\uDE00-\\uDE2F\\uDE44\\uDE80-\\uDEAA\\uDF00-\\uDF1A]|\\uD806[\\uDC00-\\uDC2B\\uDCA0-\\uDCDF\\uDCFF\\uDE00\\uDE0B-\\uDE32\\uDE3A\\uDE50\\uDE5C-\\uDE83\\uDE86-\\uDE89\\uDE9D\\uDEC0-\\uDEF8]|\\uD807[\\uDC00-\\uDC08\\uDC0A-\\uDC2E\\uDC40\\uDC72-\\uDC8F\\uDD00-\\uDD06\\uDD08\\uDD09\\uDD0B-\\uDD30\\uDD46\\uDD60-\\uDD65\\uDD67\\uDD68\\uDD6A-\\uDD89\\uDD98\\uDEE0-\\uDEF2]|\\uD808[\\uDC00-\\uDF99]|\\uD809[\\uDC00-\\uDC6E\\uDC80-\\uDD43]|[\\uD80C\\uD81C-\\uD820\\uD840-\\uD868\\uD86A-\\uD86C\\uD86F-\\uD872\\uD874-\\uD879][\\uDC00-\\uDFFF]|\\uD80D[\\uDC00-\\uDC2E]|\\uD811[\\uDC00-\\uDE46]|\\uD81A[\\uDC00-\\uDE38\\uDE40-\\uDE5E\\uDED0-\\uDEED\\uDF00-\\uDF2F\\uDF40-\\uDF43\\uDF63-\\uDF77\\uDF7D-\\uDF8F]|\\uD81B[\\uDE40-\\uDE7F\\uDF00-\\uDF44\\uDF50\\uDF93-\\uDF9F\\uDFE0\\uDFE1]|\\uD821[\\uDC00-\\uDFF1]|\\uD822[\\uDC00-\\uDEF2]|\\uD82C[\\uDC00-\\uDD1E\\uDD70-\\uDEFB]|\\uD82F[\\uDC00-\\uDC6A\\uDC70-\\uDC7C\\uDC80-\\uDC88\\uDC90-\\uDC99]|\\uD835[\\uDC00-\\uDC54\\uDC56-\\uDC9C\\uDC9E\\uDC9F\\uDCA2\\uDCA5\\uDCA6\\uDCA9-\\uDCAC\\uDCAE-\\uDCB9\\uDCBB\\uDCBD-\\uDCC3\\uDCC5-\\uDD05\\uDD07-\\uDD0A\\uDD0D-\\uDD14\\uDD16-\\uDD1C\\uDD1E-\\uDD39\\uDD3B-\\uDD3E\\uDD40-\\uDD44\\uDD46\\uDD4A-\\uDD50\\uDD52-\\uDEA5\\uDEA8-\\uDEC0\\uDEC2-\\uDEDA\\uDEDC-\\uDEFA\\uDEFC-\\uDF14\\uDF16-\\uDF34\\uDF36-\\uDF4E\\uDF50-\\uDF6E\\uDF70-\\uDF88\\uDF8A-\\uDFA8\\uDFAA-\\uDFC2\\uDFC4-\\uDFCB]|\\uD83A[\\uDC00-\\uDCC4\\uDD00-\\uDD43]|\\uD83B[\\uDE00-\\uDE03\\uDE05-\\uDE1F\\uDE21\\uDE22\\uDE24\\uDE27\\uDE29-\\uDE32\\uDE34-\\uDE37\\uDE39\\uDE3B\\uDE42\\uDE47\\uDE49\\uDE4B\\uDE4D-\\uDE4F\\uDE51\\uDE52\\uDE54\\uDE57\\uDE59\\uDE5B\\uDE5D\\uDE5F\\uDE61\\uDE62\\uDE64\\uDE67-\\uDE6A\\uDE6C-\\uDE72\\uDE74-\\uDE77\\uDE79-\\uDE7C\\uDE7E\\uDE80-\\uDE89\\uDE8B-\\uDE9B\\uDEA1-\\uDEA3\\uDEA5-\\uDEA9\\uDEAB-\\uDEBB]|\\uD869[\\uDC00-\\uDED6\\uDF00-\\uDFFF]|\\uD86D[\\uDC00-\\uDF34\\uDF40-\\uDFFF]|\\uD86E[\\uDC00-\\uDC1D\\uDC20-\\uDFFF]|\\uD873[\\uDC00-\\uDEA1\\uDEB0-\\uDFFF]|\\uD87A[\\uDC00-\\uDFE0]|\\uD87E[\\uDC00-\\uDE1D])(?:[\\\\$0-9A-Z_a-z\\xAA\\xB5\\xB7\\xBA\\xC0-\\xD6\\xD8-\\xF6\\xF8-\\u02C1\\u02C6-\\u02D1\\u02E0-\\u02E4\\u02EC\\u02EE\\u0300-\\u0374\\u0376\\u0377\\u037A-\\u037D\\u037F\\u0386-\\u038A\\u038C\\u038E-\\u03A1\\u03A3-\\u03F5\\u03F7-\\u0481\\u0483-\\u0487\\u048A-\\u052F\\u0531-\\u0556\\u0559\\u0560-\\u0588\\u0591-\\u05BD\\u05BF\\u05C1\\u05C2\\u05C4\\u05C5\\u05C7\\u05D0-\\u05EA\\u05EF-\\u05F2\\u0610-\\u061A\\u0620-\\u0669\\u066E-\\u06D3\\u06D5-\\u06DC\\u06DF-\\u06E8\\u06EA-\\u06FC\\u06FF\\u0710-\\u074A\\u074D-\\u07B1\\u07C0-\\u07F5\\u07FA\\u07FD\\u0800-\\u082D\\u0840-\\u085B\\u0860-\\u086A\\u08A0-\\u08B4\\u08B6-\\u08BD\\u08D3-\\u08E1\\u08E3-\\u0963\\u0966-\\u096F\\u0971-\\u0983\\u0985-\\u098C\\u098F\\u0990\\u0993-\\u09A8\\u09AA-\\u09B0\\u09B2\\u09B6-\\u09B9\\u09BC-\\u09C4\\u09C7\\u09C8\\u09CB-\\u09CE\\u09D7\\u09DC\\u09DD\\u09DF-\\u09E3\\u09E6-\\u09F1\\u09FC\\u09FE\\u0A01-\\u0A03\\u0A05-\\u0A0A\\u0A0F\\u0A10\\u0A13-\\u0A28\\u0A2A-\\u0A30\\u0A32\\u0A33\\u0A35\\u0A36\\u0A38\\u0A39\\u0A3C\\u0A3E-\\u0A42\\u0A47\\u0A48\\u0A4B-\\u0A4D\\u0A51\\u0A59-\\u0A5C\\u0A5E\\u0A66-\\u0A75\\u0A81-\\u0A83\\u0A85-\\u0A8D\\u0A8F-\\u0A91\\u0A93-\\u0AA8\\u0AAA-\\u0AB0\\u0AB2\\u0AB3\\u0AB5-\\u0AB9\\u0ABC-\\u0AC5\\u0AC7-\\u0AC9\\u0ACB-\\u0ACD\\u0AD0\\u0AE0-\\u0AE3\\u0AE6-\\u0AEF\\u0AF9-\\u0AFF\\u0B01-\\u0B03\\u0B05-\\u0B0C\\u0B0F\\u0B10\\u0B13-\\u0B28\\u0B2A-\\u0B30\\u0B32\\u0B33\\u0B35-\\u0B39\\u0B3C-\\u0B44\\u0B47\\u0B48\\u0B4B-\\u0B4D\\u0B56\\u0B57\\u0B5C\\u0B5D\\u0B5F-\\u0B63\\u0B66-\\u0B6F\\u0B71\\u0B82\\u0B83\\u0B85-\\u0B8A\\u0B8E-\\u0B90\\u0B92-\\u0B95\\u0B99\\u0B9A\\u0B9C\\u0B9E\\u0B9F\\u0BA3\\u0BA4\\u0BA8-\\u0BAA\\u0BAE-\\u0BB9\\u0BBE-\\u0BC2\\u0BC6-\\u0BC8\\u0BCA-\\u0BCD\\u0BD0\\u0BD7\\u0BE6-\\u0BEF\\u0C00-\\u0C0C\\u0C0E-\\u0C10\\u0C12-\\u0C28\\u0C2A-\\u0C39\\u0C3D-\\u0C44\\u0C46-\\u0C48\\u0C4A-\\u0C4D\\u0C55\\u0C56\\u0C58-\\u0C5A\\u0C60-\\u0C63\\u0C66-\\u0C6F\\u0C80-\\u0C83\\u0C85-\\u0C8C\\u0C8E-\\u0C90\\u0C92-\\u0CA8\\u0CAA-\\u0CB3\\u0CB5-\\u0CB9\\u0CBC-\\u0CC4\\u0CC6-\\u0CC8\\u0CCA-\\u0CCD\\u0CD5\\u0CD6\\u0CDE\\u0CE0-\\u0CE3\\u0CE6-\\u0CEF\\u0CF1\\u0CF2\\u0D00-\\u0D03\\u0D05-\\u0D0C\\u0D0E-\\u0D10\\u0D12-\\u0D44\\u0D46-\\u0D48\\u0D4A-\\u0D4E\\u0D54-\\u0D57\\u0D5F-\\u0D63\\u0D66-\\u0D6F\\u0D7A-\\u0D7F\\u0D82\\u0D83\\u0D85-\\u0D96\\u0D9A-\\u0DB1\\u0DB3-\\u0DBB\\u0DBD\\u0DC0-\\u0DC6\\u0DCA\\u0DCF-\\u0DD4\\u0DD6\\u0DD8-\\u0DDF\\u0DE6-\\u0DEF\\u0DF2\\u0DF3\\u0E01-\\u0E3A\\u0E40-\\u0E4E\\u0E50-\\u0E59\\u0E81\\u0E82\\u0E84\\u0E87\\u0E88\\u0E8A\\u0E8D\\u0E94-\\u0E97\\u0E99-\\u0E9F\\u0EA1-\\u0EA3\\u0EA5\\u0EA7\\u0EAA\\u0EAB\\u0EAD-\\u0EB9\\u0EBB-\\u0EBD\\u0EC0-\\u0EC4\\u0EC6\\u0EC8-\\u0ECD\\u0ED0-\\u0ED9\\u0EDC-\\u0EDF\\u0F00\\u0F18\\u0F19\\u0F20-\\u0F29\\u0F35\\u0F37\\u0F39\\u0F3E-\\u0F47\\u0F49-\\u0F6C\\u0F71-\\u0F84\\u0F86-\\u0F97\\u0F99-\\u0FBC\\u0FC6\\u1000-\\u1049\\u1050-\\u109D\\u10A0-\\u10C5\\u10C7\\u10CD\\u10D0-\\u10FA\\u10FC-\\u1248\\u124A-\\u124D\\u1250-\\u1256\\u1258\\u125A-\\u125D\\u1260-\\u1288\\u128A-\\u128D\\u1290-\\u12B0\\u12B2-\\u12B5\\u12B8-\\u12BE\\u12C0\\u12C2-\\u12C5\\u12C8-\\u12D6\\u12D8-\\u1310\\u1312-\\u1315\\u1318-\\u135A\\u135D-\\u135F\\u1369-\\u1371\\u1380-\\u138F\\u13A0-\\u13F5\\u13F8-\\u13FD\\u1401-\\u166C\\u166F-\\u167F\\u1681-\\u169A\\u16A0-\\u16EA\\u16EE-\\u16F8\\u1700-\\u170C\\u170E-\\u1714\\u1720-\\u1734\\u1740-\\u1753\\u1760-\\u176C\\u176E-\\u1770\\u1772\\u1773\\u1780-\\u17D3\\u17D7\\u17DC\\u17DD\\u17E0-\\u17E9\\u180B-\\u180D\\u1810-\\u1819\\u1820-\\u1878\\u1880-\\u18AA\\u18B0-\\u18F5\\u1900-\\u191E\\u1920-\\u192B\\u1930-\\u193B\\u1946-\\u196D\\u1970-\\u1974\\u1980-\\u19AB\\u19B0-\\u19C9\\u19D0-\\u19DA\\u1A00-\\u1A1B\\u1A20-\\u1A5E\\u1A60-\\u1A7C\\u1A7F-\\u1A89\\u1A90-\\u1A99\\u1AA7\\u1AB0-\\u1ABD\\u1B00-\\u1B4B\\u1B50-\\u1B59\\u1B6B-\\u1B73\\u1B80-\\u1BF3\\u1C00-\\u1C37\\u1C40-\\u1C49\\u1C4D-\\u1C7D\\u1C80-\\u1C88\\u1C90-\\u1CBA\\u1CBD-\\u1CBF\\u1CD0-\\u1CD2\\u1CD4-\\u1CF9\\u1D00-\\u1DF9\\u1DFB-\\u1F15\\u1F18-\\u1F1D\\u1F20-\\u1F45\\u1F48-\\u1F4D\\u1F50-\\u1F57\\u1F59\\u1F5B\\u1F5D\\u1F5F-\\u1F7D\\u1F80-\\u1FB4\\u1FB6-\\u1FBC\\u1FBE\\u1FC2-\\u1FC4\\u1FC6-\\u1FCC\\u1FD0-\\u1FD3\\u1FD6-\\u1FDB\\u1FE0-\\u1FEC\\u1FF2-\\u1FF4\\u1FF6-\\u1FFC\\u200C\\u200D\\u203F\\u2040\\u2054\\u2071\\u207F\\u2090-\\u209C\\u20D0-\\u20DC\\u20E1\\u20E5-\\u20F0\\u2102\\u2107\\u210A-\\u2113\\u2115\\u2118-\\u211D\\u2124\\u2126\\u2128\\u212A-\\u2139\\u213C-\\u213F\\u2145-\\u2149\\u214E\\u2160-\\u2188\\u2C00-\\u2C2E\\u2C30-\\u2C5E\\u2C60-\\u2CE4\\u2CEB-\\u2CF3\\u2D00-\\u2D25\\u2D27\\u2D2D\\u2D30-\\u2D67\\u2D6F\\u2D7F-\\u2D96\\u2DA0-\\u2DA6\\u2DA8-\\u2DAE\\u2DB0-\\u2DB6\\u2DB8-\\u2DBE\\u2DC0-\\u2DC6\\u2DC8-\\u2DCE\\u2DD0-\\u2DD6\\u2DD8-\\u2DDE\\u2DE0-\\u2DFF\\u3005-\\u3007\\u3021-\\u302F\\u3031-\\u3035\\u3038-\\u303C\\u3041-\\u3096\\u3099-\\u309F\\u30A1-\\u30FA\\u30FC-\\u30FF\\u3105-\\u312F\\u3131-\\u318E\\u31A0-\\u31BA\\u31F0-\\u31FF\\u3400-\\u4DB5\\u4E00-\\u9FEF\\uA000-\\uA48C\\uA4D0-\\uA4FD\\uA500-\\uA60C\\uA610-\\uA62B\\uA640-\\uA66F\\uA674-\\uA67D\\uA67F-\\uA6F1\\uA717-\\uA71F\\uA722-\\uA788\\uA78B-\\uA7B9\\uA7F7-\\uA827\\uA840-\\uA873\\uA880-\\uA8C5\\uA8D0-\\uA8D9\\uA8E0-\\uA8F7\\uA8FB\\uA8FD-\\uA92D\\uA930-\\uA953\\uA960-\\uA97C\\uA980-\\uA9C0\\uA9CF-\\uA9D9\\uA9E0-\\uA9FE\\uAA00-\\uAA36\\uAA40-\\uAA4D\\uAA50-\\uAA59\\uAA60-\\uAA76\\uAA7A-\\uAAC2\\uAADB-\\uAADD\\uAAE0-\\uAAEF\\uAAF2-\\uAAF6\\uAB01-\\uAB06\\uAB09-\\uAB0E\\uAB11-\\uAB16\\uAB20-\\uAB26\\uAB28-\\uAB2E\\uAB30-\\uAB5A\\uAB5C-\\uAB65\\uAB70-\\uABEA\\uABEC\\uABED\\uABF0-\\uABF9\\uAC00-\\uD7A3\\uD7B0-\\uD7C6\\uD7CB-\\uD7FB\\uF900-\\uFA6D\\uFA70-\\uFAD9\\uFB00-\\uFB06\\uFB13-\\uFB17\\uFB1D-\\uFB28\\uFB2A-\\uFB36\\uFB38-\\uFB3C\\uFB3E\\uFB40\\uFB41\\uFB43\\uFB44\\uFB46-\\uFBB1\\uFBD3-\\uFD3D\\uFD50-\\uFD8F\\uFD92-\\uFDC7\\uFDF0-\\uFDFB\\uFE00-\\uFE0F\\uFE20-\\uFE2F\\uFE33\\uFE34\\uFE4D-\\uFE4F\\uFE70-\\uFE74\\uFE76-\\uFEFC\\uFF10-\\uFF19\\uFF21-\\uFF3A\\uFF3F\\uFF41-\\uFF5A\\uFF66-\\uFFBE\\uFFC2-\\uFFC7\\uFFCA-\\uFFCF\\uFFD2-\\uFFD7\\uFFDA-\\uFFDC]|\\uD800[\\uDC00-\\uDC0B\\uDC0D-\\uDC26\\uDC28-\\uDC3A\\uDC3C\\uDC3D\\uDC3F-\\uDC4D\\uDC50-\\uDC5D\\uDC80-\\uDCFA\\uDD40-\\uDD74\\uDDFD\\uDE80-\\uDE9C\\uDEA0-\\uDED0\\uDEE0\\uDF00-\\uDF1F\\uDF2D-\\uDF4A\\uDF50-\\uDF7A\\uDF80-\\uDF9D\\uDFA0-\\uDFC3\\uDFC8-\\uDFCF\\uDFD1-\\uDFD5]|\\uD801[\\uDC00-\\uDC9D\\uDCA0-\\uDCA9\\uDCB0-\\uDCD3\\uDCD8-\\uDCFB\\uDD00-\\uDD27\\uDD30-\\uDD63\\uDE00-\\uDF36\\uDF40-\\uDF55\\uDF60-\\uDF67]|\\uD802[\\uDC00-\\uDC05\\uDC08\\uDC0A-\\uDC35\\uDC37\\uDC38\\uDC3C\\uDC3F-\\uDC55\\uDC60-\\uDC76\\uDC80-\\uDC9E\\uDCE0-\\uDCF2\\uDCF4\\uDCF5\\uDD00-\\uDD15\\uDD20-\\uDD39\\uDD80-\\uDDB7\\uDDBE\\uDDBF\\uDE00-\\uDE03\\uDE05\\uDE06\\uDE0C-\\uDE13\\uDE15-\\uDE17\\uDE19-\\uDE35\\uDE38-\\uDE3A\\uDE3F\\uDE60-\\uDE7C\\uDE80-\\uDE9C\\uDEC0-\\uDEC7\\uDEC9-\\uDEE6\\uDF00-\\uDF35\\uDF40-\\uDF55\\uDF60-\\uDF72\\uDF80-\\uDF91]|\\uD803[\\uDC00-\\uDC48\\uDC80-\\uDCB2\\uDCC0-\\uDCF2\\uDD00-\\uDD27\\uDD30-\\uDD39\\uDF00-\\uDF1C\\uDF27\\uDF30-\\uDF50]|\\uD804[\\uDC00-\\uDC46\\uDC66-\\uDC6F\\uDC7F-\\uDCBA\\uDCD0-\\uDCE8\\uDCF0-\\uDCF9\\uDD00-\\uDD34\\uDD36-\\uDD3F\\uDD44-\\uDD46\\uDD50-\\uDD73\\uDD76\\uDD80-\\uDDC4\\uDDC9-\\uDDCC\\uDDD0-\\uDDDA\\uDDDC\\uDE00-\\uDE11\\uDE13-\\uDE37\\uDE3E\\uDE80-\\uDE86\\uDE88\\uDE8A-\\uDE8D\\uDE8F-\\uDE9D\\uDE9F-\\uDEA8\\uDEB0-\\uDEEA\\uDEF0-\\uDEF9\\uDF00-\\uDF03\\uDF05-\\uDF0C\\uDF0F\\uDF10\\uDF13-\\uDF28\\uDF2A-\\uDF30\\uDF32\\uDF33\\uDF35-\\uDF39\\uDF3B-\\uDF44\\uDF47\\uDF48\\uDF4B-\\uDF4D\\uDF50\\uDF57\\uDF5D-\\uDF63\\uDF66-\\uDF6C\\uDF70-\\uDF74]|\\uD805[\\uDC00-\\uDC4A\\uDC50-\\uDC59\\uDC5E\\uDC80-\\uDCC5\\uDCC7\\uDCD0-\\uDCD9\\uDD80-\\uDDB5\\uDDB8-\\uDDC0\\uDDD8-\\uDDDD\\uDE00-\\uDE40\\uDE44\\uDE50-\\uDE59\\uDE80-\\uDEB7\\uDEC0-\\uDEC9\\uDF00-\\uDF1A\\uDF1D-\\uDF2B\\uDF30-\\uDF39]|\\uD806[\\uDC00-\\uDC3A\\uDCA0-\\uDCE9\\uDCFF\\uDE00-\\uDE3E\\uDE47\\uDE50-\\uDE83\\uDE86-\\uDE99\\uDE9D\\uDEC0-\\uDEF8]|\\uD807[\\uDC00-\\uDC08\\uDC0A-\\uDC36\\uDC38-\\uDC40\\uDC50-\\uDC59\\uDC72-\\uDC8F\\uDC92-\\uDCA7\\uDCA9-\\uDCB6\\uDD00-\\uDD06\\uDD08\\uDD09\\uDD0B-\\uDD36\\uDD3A\\uDD3C\\uDD3D\\uDD3F-\\uDD47\\uDD50-\\uDD59\\uDD60-\\uDD65\\uDD67\\uDD68\\uDD6A-\\uDD8E\\uDD90\\uDD91\\uDD93-\\uDD98\\uDDA0-\\uDDA9\\uDEE0-\\uDEF6]|\\uD808[\\uDC00-\\uDF99]|\\uD809[\\uDC00-\\uDC6E\\uDC80-\\uDD43]|[\\uD80C\\uD81C-\\uD820\\uD840-\\uD868\\uD86A-\\uD86C\\uD86F-\\uD872\\uD874-\\uD879][\\uDC00-\\uDFFF]|\\uD80D[\\uDC00-\\uDC2E]|\\uD811[\\uDC00-\\uDE46]|\\uD81A[\\uDC00-\\uDE38\\uDE40-\\uDE5E\\uDE60-\\uDE69\\uDED0-\\uDEED\\uDEF0-\\uDEF4\\uDF00-\\uDF36\\uDF40-\\uDF43\\uDF50-\\uDF59\\uDF63-\\uDF77\\uDF7D-\\uDF8F]|\\uD81B[\\uDE40-\\uDE7F\\uDF00-\\uDF44\\uDF50-\\uDF7E\\uDF8F-\\uDF9F\\uDFE0\\uDFE1]|\\uD821[\\uDC00-\\uDFF1]|\\uD822[\\uDC00-\\uDEF2]|\\uD82C[\\uDC00-\\uDD1E\\uDD70-\\uDEFB]|\\uD82F[\\uDC00-\\uDC6A\\uDC70-\\uDC7C\\uDC80-\\uDC88\\uDC90-\\uDC99\\uDC9D\\uDC9E]|\\uD834[\\uDD65-\\uDD69\\uDD6D-\\uDD72\\uDD7B-\\uDD82\\uDD85-\\uDD8B\\uDDAA-\\uDDAD\\uDE42-\\uDE44]|\\uD835[\\uDC00-\\uDC54\\uDC56-\\uDC9C\\uDC9E\\uDC9F\\uDCA2\\uDCA5\\uDCA6\\uDCA9-\\uDCAC\\uDCAE-\\uDCB9\\uDCBB\\uDCBD-\\uDCC3\\uDCC5-\\uDD05\\uDD07-\\uDD0A\\uDD0D-\\uDD14\\uDD16-\\uDD1C\\uDD1E-\\uDD39\\uDD3B-\\uDD3E\\uDD40-\\uDD44\\uDD46\\uDD4A-\\uDD50\\uDD52-\\uDEA5\\uDEA8-\\uDEC0\\uDEC2-\\uDEDA\\uDEDC-\\uDEFA\\uDEFC-\\uDF14\\uDF16-\\uDF34\\uDF36-\\uDF4E\\uDF50-\\uDF6E\\uDF70-\\uDF88\\uDF8A-\\uDFA8\\uDFAA-\\uDFC2\\uDFC4-\\uDFCB\\uDFCE-\\uDFFF]|\\uD836[\\uDE00-\\uDE36\\uDE3B-\\uDE6C\\uDE75\\uDE84\\uDE9B-\\uDE9F\\uDEA1-\\uDEAF]|\\uD838[\\uDC00-\\uDC06\\uDC08-\\uDC18\\uDC1B-\\uDC21\\uDC23\\uDC24\\uDC26-\\uDC2A]|\\uD83A[\\uDC00-\\uDCC4\\uDCD0-\\uDCD6\\uDD00-\\uDD4A\\uDD50-\\uDD59]|\\uD83B[\\uDE00-\\uDE03\\uDE05-\\uDE1F\\uDE21\\uDE22\\uDE24\\uDE27\\uDE29-\\uDE32\\uDE34-\\uDE37\\uDE39\\uDE3B\\uDE42\\uDE47\\uDE49\\uDE4B\\uDE4D-\\uDE4F\\uDE51\\uDE52\\uDE54\\uDE57\\uDE59\\uDE5B\\uDE5D\\uDE5F\\uDE61\\uDE62\\uDE64\\uDE67-\\uDE6A\\uDE6C-\\uDE72\\uDE74-\\uDE77\\uDE79-\\uDE7C\\uDE7E\\uDE80-\\uDE89\\uDE8B-\\uDE9B\\uDEA1-\\uDEA3\\uDEA5-\\uDEA9\\uDEAB-\\uDEBB]|\\uD869[\\uDC00-\\uDED6\\uDF00-\\uDFFF]|\\uD86D[\\uDC00-\\uDF34\\uDF40-\\uDFFF]|\\uD86E[\\uDC00-\\uDC1D\\uDC20-\\uDFFF]|\\uD873[\\uDC00-\\uDEA1\\uDEB0-\\uDFFF]|\\uD87A[\\uDC00-\\uDFE0]|\\uD87E[\\uDC00-\\uDE1D]|\\uDB40[\\uDD00-\\uDDEF])*$/\n  )\n  return regex.test(str)\n}\n\nexport default isVarName\n"
  },
  {
    "path": "src/utils/parser.js",
    "content": "import * as THREE from 'three'\nimport * as prettier from 'prettier'\nimport babelParser from 'prettier/parser-babel.js'\nimport isVarName from './isVarName.js'\n\nfunction parse(gltf, { fileName = 'model', ...options } = {}) {\n  if (gltf.isObject3D) {\n    // Wrap scene in a GLTF Structure\n    gltf = { scene: gltf, animations: [], parser: { json: {} } }\n  }\n\n  const url = (fileName.toLowerCase().startsWith('http') ? '' : '/') + fileName\n  const animations = gltf.animations\n  const hasAnimations = animations.length > 0\n\n  // Collect all objects\n  const objects = []\n  gltf.scene.traverse((child) => objects.push(child))\n\n  // Browse for duplicates\n  const duplicates = {\n    names: {},\n    materials: {},\n    geometries: {},\n  }\n\n  function uniqueName(attempt, index = 0) {\n    const newAttempt = index > 0 ? attempt + index : attempt\n    if (Object.values(duplicates.geometries).find(({ name }) => name === newAttempt) === undefined) return newAttempt\n    else return uniqueName(attempt, index + 1)\n  }\n\n  gltf.scene.traverse((child) => {\n    if (child.isMesh) {\n      if (child.material) {\n        if (!duplicates.materials[child.material.name]) {\n          duplicates.materials[child.material.name] = 1\n        } else {\n          duplicates.materials[child.material.name]++\n        }\n      }\n    }\n  })\n\n  gltf.scene.traverse((child) => {\n    if (child.isMesh) {\n      if (child.geometry) {\n        const key = child.geometry.uuid + child.material?.name ?? ''\n        if (!duplicates.geometries[key]) {\n          let name = (child.name || 'Part').replace(/[^a-zA-Z]/g, '')\n          name = name.charAt(0).toUpperCase() + name.slice(1)\n          duplicates.geometries[key] = {\n            count: 1,\n            name: uniqueName(name),\n            node: 'nodes' + sanitizeName(child.name),\n          }\n        } else {\n          duplicates.geometries[key].count++\n        }\n      }\n    }\n  })\n\n  // Prune duplicate geometries\n  if (!options.instanceall) {\n    for (let key of Object.keys(duplicates.geometries)) {\n      const duplicate = duplicates.geometries[key]\n      if (duplicate.count === 1) delete duplicates.geometries[key]\n    }\n  }\n\n  const hasInstances = (options.instance || options.instanceall) && Object.keys(duplicates.geometries).length > 0\n\n  function sanitizeName(name) {\n    return isVarName(name) ? `.${name}` : `['${name}']`\n  }\n\n  const rNbr = (number) => {\n    return parseFloat(number.toFixed(Math.round(options.precision || 2)))\n  }\n\n  const rDeg = (number) => {\n    const abs = Math.abs(Math.round(parseFloat(number) * 100000))\n    for (let i = 1; i <= 10; i++) {\n      if (abs === Math.round(parseFloat(Math.PI / i) * 100000))\n        return `${number < 0 ? '-' : ''}Math.PI${i > 1 ? ' / ' + i : ''}`\n    }\n    for (let i = 1; i <= 10; i++) {\n      if (abs === Math.round(parseFloat(Math.PI * i) * 100000))\n        return `${number < 0 ? '-' : ''}Math.PI${i > 1 ? ' * ' + i : ''}`\n    }\n    return rNbr(number)\n  }\n\n  function printTypes(objects, animations) {\n    let meshes = objects.filter((o) => o.isMesh && o.__removed === undefined)\n    let bones = objects.filter((o) => o.isBone && !(o.parent && o.parent.isBone) && o.__removed === undefined)\n    let materials = [...new Set(objects.filter((o) => o.material && o.material.name).map((o) => o.material))]\n\n    let animationTypes = ''\n    if (animations.length) {\n      animationTypes = `\\n\n  type ActionName = ${animations.map((clip, i) => `\"${clip.name}\"`).join(' | ')};\n\n  interface GLTFAction extends THREE.AnimationClip { name: ActionName }\\n`\n    }\n\n    const types = [...new Set([...meshes, ...bones].map((o) => getType(o)))]\n    const contextType = hasInstances\n      ? `\\ntype ContextType = Record<string, React.ForwardRefExoticComponent<\n     ${types.map((type) => `JSX.IntrinsicElements['${type}']`).join(' | ')}\n    >>\\n`\n      : ''\n\n    return `\\n${animationTypes}\\ntype GLTFResult = GLTF & {\n    nodes: {\n      ${meshes.map(({ name, type }) => (isVarName(name) ? name : `['${name}']`) + ': THREE.' + type).join(',')}\n      ${bones.map(({ name, type }) => (isVarName(name) ? name : `['${name}']`) + ': THREE.' + type).join(',')}\n    }\n    materials: {\n      ${materials.map(({ name, type }) => (isVarName(name) ? name : `['${name}']`) + ': THREE.' + type).join(',')}\n    }\n    animations: GLTFAction[]\n  }\\n${contextType}`\n  }\n\n  function getType(obj) {\n    let type = obj.type.charAt(0).toLowerCase() + obj.type.slice(1)\n    // Turn object3d's into groups, it should be faster according to the threejs docs\n    if (type === 'object3D') type = 'group'\n    if (type === 'perspectiveCamera') type = 'PerspectiveCamera'\n    if (type === 'orthographicCamera') type = 'OrthographicCamera'\n    return type\n  }\n\n  function handleProps(obj) {\n    let { type, node, instanced } = getInfo(obj)\n\n    let result = ''\n    let isCamera = type === 'PerspectiveCamera' || type === 'OrthographicCamera'\n    // Handle cameras\n    if (isCamera) {\n      result += `makeDefault={false} `\n      if (obj.zoom !== 1) result += `zoom={${rNbr(obj.zoom)}} `\n      if (obj.far !== 2000) result += `far={${rNbr(obj.far)}} `\n      if (obj.near !== 0.1) result += `near={${rNbr(obj.near)}} `\n    }\n    if (type === 'PerspectiveCamera') {\n      if (obj.fov !== 50) result += `fov={${rNbr(obj.fov)}} `\n    }\n\n    if (!instanced) {\n      // Shadows\n      if (type === 'mesh' && options.shadows) result += `castShadow receiveShadow `\n\n      // Write out geometry first\n      if (obj.geometry && !obj.isInstancedMesh) {\n        result += `geometry={${node}.geometry} `\n      }\n\n      // Write out materials\n      if (obj.material && !obj.isInstancedMesh) {\n        if (obj.material.name) result += `material={materials${sanitizeName(obj.material.name)}} `\n        else result += `material={${node}.material} `\n      }\n\n      if (obj.instanceMatrix) result += `instanceMatrix={${node}.instanceMatrix} `\n      if (obj.instanceColor) result += `instanceColor={${node}.instanceColor} `\n      if (obj.skeleton) result += `skeleton={${node}.skeleton} `\n      if (obj.visible === false) result += `visible={false} `\n      if (obj.castShadow === true) result += `castShadow `\n      if (obj.receiveShadow === true) result += `receiveShadow `\n      if (obj.morphTargetDictionary) result += `morphTargetDictionary={${node}.morphTargetDictionary} `\n      if (obj.morphTargetInfluences) result += `morphTargetInfluences={${node}.morphTargetInfluences} `\n      if (obj.intensity && rNbr(obj.intensity)) result += `intensity={${rNbr(obj.intensity)}} `\n      //if (obj.power && obj.power !== 4 * Math.PI) result += `power={${rNbr(obj.power)}} `\n      if (obj.angle && obj.angle !== Math.PI / 3) result += `angle={${rDeg(obj.angle)}} `\n      if (obj.penumbra && rNbr(obj.penumbra) !== 0) result += `penumbra={${rNbr(obj.penumbra)}} `\n      if (obj.decay && rNbr(obj.decay) !== 1) result += `decay={${rNbr(obj.decay)}} `\n      if (obj.distance && rNbr(obj.distance) !== 0) result += `distance={${rNbr(obj.distance)}} `\n      if (obj.up && obj.up.isVector3 && !obj.up.equals(new THREE.Vector3(0, 1, 0)))\n        result += `up={[${rNbr(obj.up.x)}, ${rNbr(obj.up.y)}, ${rNbr(obj.up.z)},]} `\n    }\n\n    if (obj.color && obj.color.getHexString() !== 'ffffff') result += `color=\"#${obj.color.getHexString()}\" `\n    if (obj.position && obj.position.isVector3 && rNbr(obj.position.length()))\n      result += `position={[${rNbr(obj.position.x)}, ${rNbr(obj.position.y)}, ${rNbr(obj.position.z)},]} `\n    if (\n      obj.rotation &&\n      obj.rotation.isEuler &&\n      rNbr(new THREE.Vector3(obj.rotation.x, obj.rotation.y, obj.rotation.z).length())\n    )\n      result += `rotation={[${rDeg(obj.rotation.x)}, ${rDeg(obj.rotation.y)}, ${rDeg(obj.rotation.z)},]} `\n    if (\n      obj.scale &&\n      obj.scale.isVector3 &&\n      !(rNbr(obj.scale.x) === 1 && rNbr(obj.scale.y) === 1 && rNbr(obj.scale.z) === 1)\n    ) {\n      const rX = rNbr(obj.scale.x)\n      const rY = rNbr(obj.scale.y)\n      const rZ = rNbr(obj.scale.z)\n      if (rX === rY && rX === rZ) {\n        result += `scale={${rX}} `\n      } else {\n        result += `scale={[${rX}, ${rY}, ${rZ},]} `\n      }\n    }\n    if (options.meta && obj.userData && Object.keys(obj.userData).length)\n      result += `userData={${JSON.stringify(obj.userData)}} `\n\n    return result\n  }\n\n  function getInfo(obj) {\n    let type = getType(obj)\n    let node = 'nodes' + sanitizeName(obj.name)\n    let instanced =\n      (options.instance || options.instanceall) &&\n      obj.geometry &&\n      obj.material &&\n      duplicates.geometries[obj.geometry.uuid + obj.material.name] &&\n      duplicates.geometries[obj.geometry.uuid + obj.material.name].count > (options.instanceall ? 0 : 1)\n    let animated = gltf.animations && gltf.animations.length > 0\n    return { type, node, instanced, animated }\n  }\n\n  function equalOrNegated(a, b) {\n    return (a.x === b.x || a.x === -b.x) && (a.y === b.y || a.y === -b.y) && (a.z === b.z || a.z === -b.z)\n  }\n\n  function prune(obj, children, result, oldResult, silent) {\n    let { type, animated } = getInfo(obj)\n    // Prune ...\n    if (!obj.__removed && !options.keepgroups && !animated && (type === 'group' || type === 'scene')) {\n      /** Empty or no-property groups\n       *    <group>\n       *      <mesh geometry={nodes.foo} material={materials.bar} />\n       *  Solution:\n       *    <mesh geometry={nodes.foo} material={materials.bar} />\n       */\n      if (result === oldResult || obj.children.length === 0) {\n        if (options.debug && !silent) console.log(`group ${obj.name} removed (empty)`)\n        obj.__removed = true\n        return children\n      }\n\n      // More aggressive removal strategies ...\n      const first = obj.children[0]\n      const firstProps = handleProps(first)\n      const regex = /([a-z-A-Z]*)={([a-zA-Z0-9\\.\\[\\]\\-\\,\\ \\/]*)}/g\n      const keys1 = [...result.matchAll(regex)].map(([, match]) => match)\n      const values1 = [...result.matchAll(regex)].map(([, , match]) => match)\n      const keys2 = [...firstProps.matchAll(regex)].map(([, match]) => match)\n\n      /** Double negative rotations\n       *    <group rotation={[-Math.PI / 2, 0, 0]}>\n       *      <group rotation={[Math.PI / 2, 0, 0]}>\n       *        <mesh geometry={nodes.foo} material={materials.bar} />\n       *  Solution:\n       *    <mesh geometry={nodes.foo} material={materials.bar} />\n       */\n      if (obj.children.length === 1 && getType(first) === type && equalOrNegated(obj.rotation, first.rotation)) {\n        if (keys1.length === 1 && keys2.length === 1 && keys1[0] === 'rotation' && keys2[0] === 'rotation') {\n          if (options.debug && !silent) console.log(`group ${obj.name} removed (aggressive: double negative rotation)`)\n          obj.__removed = first.__removed = true\n          children = ''\n          if (first.children) first.children.forEach((child) => (children += print(child, true)))\n          return children\n        }\n      }\n\n      /** Double negative rotations w/ props\n       *    <group rotation={[-Math.PI / 2, 0, 0]}>\n       *      <group rotation={[Math.PI / 2, 0, 0]} scale={0.01}>\n       *        <mesh geometry={nodes.foo} material={materials.bar} />\n       *  Solution:\n       *    <group scale={0.01}>\n       *      <mesh geometry={nodes.foo} material={materials.bar} />\n       */\n      if (obj.children.length === 1 && getType(first) === type && equalOrNegated(obj.rotation, first.rotation)) {\n        if (keys1.length === 1 && keys2.length > 1 && keys1[0] === 'rotation' && keys2.includes('rotation')) {\n          if (options.debug && !silent)\n            console.log(`group ${obj.name} removed (aggressive: double negative rotation w/ props)`)\n          obj.__removed = true\n          // Remove rotation from first child\n          first.rotation.set(0, 0, 0)\n          children = print(first, true)\n          return children\n        }\n      }\n\n      /** Transform overlap\n       *    <group position={[10, 0, 0]} scale={2} rotation={[-Math.PI / 2, 0, 0]}>\n       *      <mesh geometry={nodes.foo} material={materials.bar} />\n       *  Solution:\n       *    <mesh geometry={nodes.foo} material={materials.bar} position={[10, 0, 0]} scale={2} rotation={[-Math.PI / 2, 0, 0]} />\n       */\n      const isChildTransformed = keys2.includes('position') || keys2.includes('rotation') || keys2.includes('scale')\n      const hasOtherProps = keys1.some((key) => !['position', 'scale', 'rotation'].includes(key))\n      if (obj.children.length === 1 && !first.__removed && !isChildTransformed && !hasOtherProps) {\n        if (options.debug && !silent) console.log(`group ${obj.name} removed (aggressive: ${keys1.join(' ')} overlap)`)\n        // Move props over from the to-be-deleted object to the child\n        // This ensures that the child will have the correct transform when pruning is being repeated\n        keys1.forEach((key) => obj.children[0][key].copy(obj[key]))\n        // Insert the props into the result string\n        children = print(first, true)\n        obj.__removed = true\n        return children\n      }\n\n      /** Lack of content\n       *    <group position={[10, 0, 0]} scale={2} rotation={[-Math.PI / 2, 0, 0]}>\n       *      <group position={[10, 0, 0]} scale={2} rotation={[-Math.PI / 2, 0, 0]}>\n       *        <group position={[10, 0, 0]} scale={2} rotation={[-Math.PI / 2, 0, 0]} />\n       * Solution:\n       *   (delete the whole sub graph)\n       */\n      const empty = []\n      obj.traverse((o) => {\n        const type = getType(o)\n        if (type !== 'group' && type !== 'object3D') empty.push(o)\n      })\n      if (!empty.length) {\n        if (options.debug && !silent) console.log(`group ${obj.name} removed (aggressive: lack of content)`)\n        empty.forEach((child) => (child.__removed = true))\n        return ''\n      }\n    }\n  }\n\n  function print(obj, silent = false) {\n    let result = ''\n    let children = ''\n    let { type, node, instanced, animated } = getInfo(obj)\n\n    // Check if the root node is useless\n    if (obj.__removed && obj.children.length) {\n      obj.children.forEach((child) => (result += print(child)))\n      return result\n    }\n\n    // Bail out on bones\n    if (!options.bones && type === 'bone') {\n      return `<primitive object={${node}} />`\n    }\n\n    // Take care of lights with targets\n    if (type.endsWith('Light') && obj.target && obj.children[0] === obj.target) {\n      return `<${type} ${handleProps(obj)} target={${node}.target}>\n        <primitive object={${node}.target} ${handleProps(obj.target)} />\n      </${type}>`\n    }\n\n    // Collect children\n    if (obj.children) obj.children.forEach((child) => (children += print(child)))\n\n    if (instanced) {\n      result = `<instances.${duplicates.geometries[obj.geometry.uuid + obj.material.name].name} `\n      type = `instances.${duplicates.geometries[obj.geometry.uuid + obj.material.name].name}`\n    } else {\n      if (obj.isInstancedMesh) {\n        const geo = `${node}.geometry`\n        const mat = obj.material.name ? `materials${sanitizeName(obj.material.name)}` : `${node}.material`\n        type = \"instancedMesh\"\n        result = `<instancedMesh args={[${geo}, ${mat}, ${!obj.count ? `${node}.count` : obj.count}]} `\n      } else {\n        // Form the object in JSX syntax\n        if (type === 'bone') result = `<primitive object={${node}} `\n        else result = `<${type} `\n      }\n    }\n\n    // Include names when output is uncompressed or morphTargetDictionaries are present\n    if (obj.name.length && (options.keepnames || obj.morphTargetDictionary || animated)) result += `name=\"${obj.name}\" `\n\n    const oldResult = result\n    result += handleProps(obj)\n\n    const pruned = prune(obj, children, result, oldResult, silent)\n    // Bail out if the object was pruned\n    if (pruned !== undefined) return pruned\n\n    // Close tag\n    result += `${children.length ? '>' : '/>'}\\n`\n\n    // Add children and return\n    if (children.length) {\n      if (type === 'bone') result += children + `</primitive>`\n      else result += children + `</${type}>`\n    }\n    return result\n  }\n\n  function printAnimations(animations) {\n    return animations.length ? `\\nconst { actions } = useAnimations(animations, group)` : ''\n  }\n\n  function parseExtras(extras) {\n    if (extras) {\n      return (\n        Object.keys(extras)\n          .map((key) => `${key.charAt(0).toUpperCase() + key.slice(1)}: ${extras[key]}`)\n          .join('\\n') + '\\n'\n      )\n    } else return ''\n  }\n\n  function p(obj, line) {\n    console.log(\n      [...new Array(line * 2)].map(() => ' ').join(''),\n      obj.type,\n      obj.name,\n      'pos:',\n      obj.position.toArray().map(rNbr),\n      'scale:',\n      obj.scale.toArray().map(rNbr),\n      'rot:',\n      [obj.rotation.x, obj.rotation.y, obj.rotation.z].map(rNbr),\n      'mat:',\n      obj.material ? `${obj.material.name}-${obj.material.uuid.substring(0, 8)}` : ''\n    )\n    obj.children.forEach((o) => p(o, line + 1))\n  }\n\n  if (options.debug) p(gltf.scene, 0)\n\n  let scene\n  try {\n    if (!options.keepgroups) {\n      // Dry run to prune graph\n      print(gltf.scene)\n      // Move children of deleted objects to their new parents\n      objects.forEach((o) => {\n        if (o.__removed) {\n          let parent = o.parent\n          // Making sure we don't add to a removed parent\n          while (parent && parent.__removed) parent = parent.parent\n          // If no parent was found it must be the root node\n          if (!parent) parent = gltf.scene\n          o.children.slice().forEach((child) => parent.add(child))\n        }\n      })\n      // Remove deleted objects\n      objects.forEach((o) => {\n        if (o.__removed && o.parent) o.parent.remove(o)\n      })\n    }\n    // 2nd pass to eliminate hard to swat left-overs\n    scene = print(gltf.scene)\n  } catch (e) {\n    console.log('Error while parsing glTF', e)\n  }\n  const header = `/*\n${options.header ? options.header : 'Auto-generated by: https://github.com/pmndrs/gltfjsx'} ${\n    options.size ? `\\nFiles: ${options.size}` : ''\n  }\n${parseExtras(gltf.parser.json.asset && gltf.parser.json.asset.extras)}*/`\n  const hasPrimitives = scene.includes('<primitive')\n  const result = `${options.types ? `\\nimport * as THREE from 'three'` : ''}\n        import React from 'react'${hasPrimitives ? '\\nimport { useGraph } from \"@react-three/fiber\"' : ''}\n        import { useGLTF, ${hasInstances ? 'Merged, ' : ''} ${\n          scene.includes('PerspectiveCamera') ? 'PerspectiveCamera,' : ''\n        }\n        ${scene.includes('OrthographicCamera') ? 'OrthographicCamera,' : ''}\n        ${hasAnimations ? 'useAnimations' : ''} } from '@react-three/drei'\n        ${\n          hasPrimitives || options.types\n            ? `import { ${options.types ? 'GLTF,' : ''} ${hasPrimitives ? 'SkeletonUtils' : ''} } from \"three-stdlib\"`\n            : ''\n        }\n        ${options.types ? printTypes(objects, animations) : ''}\n\n        ${\n          hasInstances\n            ? `\n        const context = React.createContext(${options.types ? '{} as ContextType' : ''})\n\n        export function Instances({ children, ...props }${options.types ? ': JSX.IntrinsicElements[\"group\"]' : ''}) {\n          const { nodes } = useGLTF('${url}'${options.draco ? `, ${JSON.stringify(options.draco)}` : ''})${\n            options.types ? ' as GLTFResult' : ''\n          }\n          const instances = React.useMemo(() => ({\n            ${Object.values(duplicates.geometries)\n              .map((v) => `${v.name}: ${v.node}`)\n              .join(', ')}\n          }), [nodes])\n          return (\n            <Merged meshes={instances} {...props}>\n              {(instances${\n                options.types ? ': ContextType' : ''\n              }) => <context.Provider value={instances} children={children} />}\n            </Merged>\n          )\n        }\n        `\n            : ''\n        }\n\n        export ${options.exportdefault ? 'default' : ''} function Model(props${\n          options.types ? \": JSX.IntrinsicElements['group']\" : ''\n        }) {\n          ${hasInstances ? 'const instances = React.useContext(context);' : ''} ${\n            hasAnimations ? `const group = ${options.types ? 'React.useRef<THREE.Group>()' : 'React.useRef()'};` : ''\n          } ${\n            !options.instanceall\n              ? `const { ${!hasPrimitives ? `nodes, materials` : 'scene'} ${hasAnimations ? ', animations' : ''}} = useGLTF('${url}'${\n                  options.draco ? `, ${JSON.stringify(options.draco)}` : ''\n                })${!hasPrimitives && options.types ? ' as GLTFResult' : ''}${\n                  hasPrimitives\n                    ? `\\nconst clone = React.useMemo(() => SkeletonUtils.clone(scene), [scene])\n                const { nodes, materials } = useGraph(clone) ${options.types ? ' as GLTFResult' : ''}`\n                    : ''\n                }`\n              : ''\n          } ${printAnimations(animations)}\n          return (\n            <group ${hasAnimations ? `ref={group}` : ''} {...props} dispose={null}>\n        ${scene}\n            </group>\n          )\n        }\n\nuseGLTF.preload('${url}')`\n\n  if (!options.console) console.log(header)\n  const output = header + '\\n' + result\n  const formatted = prettier.format(output, {\n    semi: false,\n    printWidth: options.printwidth || 1000,\n    singleQuote: true,\n    jsxBracketSameLine: true,\n    parser: 'babel-ts',\n    plugins: [babelParser],\n  })\n  return formatted\n}\n\nexport default parse\n"
  },
  {
    "path": "src/utils/transform.js",
    "content": "import { Logger, NodeIO } from '@gltf-transform/core'\nimport {\n  simplify,\n  instance,\n  flatten,\n  dequantize,\n  reorder,\n  join,\n  weld,\n  sparse,\n  dedup,\n  resample,\n  prune,\n  textureCompress,\n  draco,\n  palette,\n  unpartition,\n} from '@gltf-transform/functions'\nimport { ALL_EXTENSIONS } from '@gltf-transform/extensions'\nimport { MeshoptDecoder, MeshoptEncoder, MeshoptSimplifier } from 'meshoptimizer'\nimport { ready as resampleReady, resample as resampleWASM } from 'keyframe-resample'\nimport draco3d from 'draco3dgltf'\nimport sharp from 'sharp'\n\nasync function transform(file, output, config = {}) {\n  await MeshoptDecoder.ready\n  await MeshoptEncoder.ready\n  const io = new NodeIO().registerExtensions(ALL_EXTENSIONS).registerDependencies({\n    'draco3d.decoder': await draco3d.createDecoderModule(),\n    'draco3d.encoder': await draco3d.createEncoderModule(),\n    'meshopt.decoder': MeshoptDecoder,\n    'meshopt.encoder': MeshoptEncoder,\n  })\n  if (config.console) io.setLogger(new Logger(Logger.Verbosity.ERROR))\n  else io.setLogger(new Logger(Logger.Verbosity.WARN))\n\n  const document = await io.read(file)\n  const resolution = config.resolution ?? 1024\n  const normalResolution = Math.max(resolution, 2048)\n  const degradeResolution = config.degraderesolution ?? 512\n  const functions = [unpartition()]\n\n  if (!config.keepmaterials) functions.push(palette({ min: 5 }))\n\n  functions.push(\n    reorder({ encoder: MeshoptEncoder }),\n    dedup(),\n    // This seems problematic ...\n    // instance({ min: 5 }),\n    flatten(),\n    dequantize() // ...\n  )\n\n  if (!config.keepmeshes) {\n    functions.push(\n      join() // ...\n    )\n  }\n\n  functions.push(\n\t  // Weld vertices\n\t  weld(),\n  )\n\n  if (config.simplify) {\n    functions.push(\n      // Simplify meshes\n      simplify({ simplifier: MeshoptSimplifier, ratio: config.ratio ?? 0, error: config.error ?? 0.0001 })\n    )\n  }\n\n  functions.push(\n    resample({ ready: resampleReady, resample: resampleWASM }),\n    prune({ keepAttributes: false, keepLeaves: false }),\n    sparse()\n  )\n\n  if (config.degrade) {\n    // Custom per-file resolution\n    functions.push(\n      textureCompress({\n        encoder: sharp,\n        pattern: new RegExp(`^(?=${config.degrade}).*$`),\n        targetFormat: config.format,\n        resize: [degradeResolution, degradeResolution],\n      }),\n      textureCompress({\n        encoder: sharp,\n        pattern: new RegExp(`^(?!${config.degrade}).*$`),\n        targetFormat: config.format,\n        resize: [resolution, resolution],\n      })\n    )\n  } else {\n    // Keep normal maps near lossless\n    functions.push(\n      textureCompress({\n        slots: /^(?!normalTexture).*$/, // exclude normal maps\n        encoder: sharp,\n        targetFormat: config.format,\n        resize: [resolution, resolution],\n      }),\n      textureCompress({\n        slots: /^(?=normalTexture).*$/, // include normal maps\n        encoder: sharp,\n        targetFormat: 'jpeg',\n        resize: [normalResolution, normalResolution],\n      })\n    )\n  }\n\n  functions.push(draco())\n\n  await document.transform(...functions)\n  await io.write(output, document)\n}\n\nexport default transform\n"
  }
]