ronantakizawa/codereview-bench huggingface dataset:
Repository: moeru-ai/airi
File: packages/stage-ui/src/components/Scenarios/Settings/ModelSettings/VRMScene.vue (Vue)

Code before:
<script setup lang="ts">
import { useVRM } from '@proj-airi/stage-ui/stores'
import { OrbitControls } from '@tresjs/cientos'
import { TresCanvas } from '@tresjs/core'
import { useElementBounding } from '@vueuse/core'
import { storeToRefs } from 'pinia'
import { computed, ref } from 'vue'

import { VRMModel } from '../../../Scenes'

const emit = defineEmits<{
  (e: 'loadModelProgress', value: number): void
  (e: 'error', value: unknown): void
}>()
const VRMContainerRef = ref<HTMLDivElement>()
const { width, height } = useElementBounding(VRMContainerRef)
const { modelFile, modelUrl, loadSource } = storeToRefs(useVRM())

const cameraPositionX = ref(-0.17)
const cameraPositionY = ref(0)
const cameraPositionZ = ref(-1)
const vrmModelPositionX = ref(-0.18)
const vrmModelPositionY = ref(-1.32)
const vrmModelPositionZ = ref(-0.24)

const modelRef = ref<{
  setExpression: (expression: string) => void
}>()

defineExpose({
  setExpression: (expression: string) => {
    modelRef.value?.setExpression(expression)
  },
})

const selectedModel = computed(() => {
  if (loadSource.value === 'file' && modelFile.value) {
    return URL.createObjectURL(modelFile.value)
  }
  else if (loadSource.value === 'url' && modelUrl.value) {
    return modelUrl.value
  }

Review comment (suggestion):
```suggestion
const { modelFile, modelUrl, loadSource, selectedModel } = storeToRefs(useVRM())
```

Code after:
<script setup lang="ts">
import { useVRM } from '@proj-airi/stage-ui/stores'
import { OrbitControls } from '@tresjs/cientos'
import { TresCanvas } from '@tresjs/core'
import { useElementBounding } from '@vueuse/core'
import { storeToRefs } from 'pinia'
import { computed, ref } from 'vue'

import { VRMModel } from '../../../Scenes'

const emit = defineEmits<{
  (e: 'loadModelProgress', value: number): void
  (e: 'error', value: unknown): void
}>()
const VRMContainerRef = ref<HTMLDivElement>()
const { width, height } = useElementBounding(VRMContainerRef)
const { modelFile, modelUrl, loadSource, selectedModel } = storeToRefs(useVRM())

const cameraPositionX = ref(-0.17)
const cameraPositionY = ref(0)
const cameraPositionZ = ref(-1)
const vrmModelPositionX = ref(-0.18)
const vrmModelPositionY = ref(-1.32)
const vrmModelPositionZ = ref(-0.24)

const modelRef = ref<{
  setExpression: (expression: string) => void
}>()

defineExpose({
  setExpression: (expression: string) => {
    modelRef.value?.setExpression(expression)
  },
})

</script>

<template>
  <div ref="VRMContainerRef" w="100%" h="100%">
    <TresCanvas :alpha="true" :antialias="true" :width="width" :height="height">
      <OrbitControls />
      <TresPerspectiveCamera :position="[cameraPositionX, cameraPositionY, cameraPositionZ]" />
Repository: moeru-ai/airi
File: packages/stage-ui/src/stores/vrm.ts (TypeScript)

Code before:
	      modelObjectUrl.value = URL.createObjectURL(newFile)
	    }
	  })
	
	  // Centralized computed property for the model source
	  const selectedModel = computed(() => {
	    if (loadSource.value === 'file' && modelObjectUrl.value) {
	      return modelObjectUrl.value
	    }
	    if (loadSource.value === 'url' && modelUrl.value) {
	      return modelUrl.value
	    }
	    // Fallback model
	    return '/assets/vrm/models/AvatarSample-B/AvatarSample_B.vrm'
	  })
	
	  return {
	    modelFile,
	    modelUrl,
	    loadSource,
	    loadingModel,
	    position,
	    positionInPercentageString,
	    selectedModel, // Expose the new computed property
	  }
	})


Review comment (bug):
```suggestion
import { defineStore } from 'pinia'
import { computed, ref, watch } from 'vue'

export const useVRM = defineStore('vrm', () => {
  const modelFile = ref<File>()
  const modelUrl = ref<string>('/assets/vrm/models/AvatarSample-B/AvatarSample_B.vrm')
  const loadSource = ref<'file' | 'url'>('url')
  const loadingModel = ref(false)
  const position = useLocalStorage('settings/vrm/position', { x: 0, y: 0 })
  const positionInPercentageString = computed(() => ({
  x: `${position.value.x}%`,
  y: `${position.value.y}%`,
  }))

  const modelObjectUrl = ref<string>()

  // Manage the object URL lifecycle to prevent memory leaks
  watch(modelFile, (newFile) => {
  if (modelObjectUrl.value) {
    URL.revokeObjectURL(modelObjectUrl.value)
    modelObjectUrl.value = undefined
  }
  if (newFile) {
    modelObjectUrl.value = URL.createObjectURL(newFile)
  }
  })

  // Centralized computed property for the model source
  const selectedModel = computed(() => {
  if (loadSource.value === 'file' && modelObjectUrl.value) {
    return modelObjectUrl.value
  }
  if (loadSource.value === 'url' && modelUrl.value) {
    return modelUrl.value
  }
  // Fallback model
  return '/assets/vrm/models/AvatarSample-B/AvatarSample_B.vrm'
  })

  return {
  modelFile,
  modelUrl,
  loadSource,
  loadingModel,
  position,
  positionInPercentageString,
  selectedModel, // Expose the new computed property
  }
})
```

Code after:
      modelObjectUrl.value = URL.createObjectURL(newFile)
    }
  })

  // Centralized computed property for the model source
  const selectedModel = computed(() => {
    if (loadSource.value === 'file' && modelObjectUrl.value) {
      return modelObjectUrl.value
    }
    if (loadSource.value === 'url' && modelUrl.value) {
      return modelUrl.value
    }
    // Fallback model
    return '/assets/vrm/models/AvatarSample-B/AvatarSample_B.vrm'
  })

  return {
    modelFile,
    modelUrl,
    loadSource,
    loadingModel,
    position,
    positionInPercentageString,
    selectedModel, // Expose the new computed property
  }
})
Repository: moeru-ai/airi
File: packages/stage-ui/src/stores/vrm.ts (TypeScript)

Code before:
    modelObjectUrl.value = URL.createObjectURL(newFile)
  }
  })

  // Centralized computed property for the model source
  const selectedModel = computed(() => {
  if (loadSource.value === 'file' && modelObjectUrl.value) {
    return modelObjectUrl.value
  }
  if (loadSource.value === 'url' && modelUrl.value) {
    return modelUrl.value
  }
  // Fallback model
  return '/assets/vrm/models/AvatarSample-B/AvatarSample_B.vrm'
  })

  return {
  modelFile,
  modelUrl,
  loadSource,
  loadingModel,
  position,
  positionInPercentageString,
  selectedModel, // Expose the new computed property
  }
})


Review comment (bug):
```suggestion
import { useLocalStorage } from '@vueuse/core'
import { defineStore } from 'pinia'
import { computed, ref, watch } from 'vue'

export const useVRM = defineStore('vrm', () => {
  const modelFile = ref<File>()
  const modelUrl = ref<string>('/assets/vrm/models/AvatarSample-B/AvatarSample_B.vrm')
  const loadSource = ref<'file' | 'url'>('url')
  const loadingModel = ref(false)
  const position = useLocalStorage('settings/vrm/position', { x: 0, y: 0 })
  const positionInPercentageString = computed(() => ({
    x: `${position.value.x}%`,
    y: `${position.value.y}%`,
  }))

  const modelObjectUrl = ref<string>()

  // Manage the object URL lifecycle to prevent memory leaks
  watch(modelFile, (newFile) => {
    if (modelObjectUrl.value) {
      URL.revokeObjectURL(modelObjectUrl.value)
      modelObjectUrl.value = undefined
    }
    if (newFile) {
      modelObjectUrl.value = URL.createObjectURL(newFile)
    }
  })

  // Centralized computed property for the model source
  const selectedModel = computed(() => {
    if (loadSource.value === 'file' && modelObjectUrl.value) {
      return modelObjectUrl.value
    }
    if (loadSource.value === 'url' && modelUrl.value) {
      return modelUrl.value
    }
    // Fallback model
    return '/assets/vrm/models/AvatarSample-B/AvatarSample_B.vrm'
  })

  return {
    modelFile,
    modelUrl,
    loadSource,
    loadingModel,
    position,
    positionInPercentageString,
    selectedModel, // Expose the new computed property
  }
})

```

Code after:
      modelObjectUrl.value = URL.createObjectURL(newFile)
    }
  })

  // Centralized computed property for the model source
  const selectedModel = computed(() => {
    if (loadSource.value === 'file' && modelObjectUrl.value) {
      return modelObjectUrl.value
    }
    if (loadSource.value === 'url' && modelUrl.value) {
      return modelUrl.value
    }
    // Fallback model
    return '/assets/vrm/models/AvatarSample-B/AvatarSample_B.vrm'
  })

  return {
    modelFile,
    modelUrl,
    loadSource,
    loadingModel,
    position,
    positionInPercentageString,
    selectedModel, // Expose the new computed property
  }
})
Repository: moeru-ai/airi
File: packages/stage-ui/src/components/Misc/ErrorContainer.vue (Vue)

Code before:
<script setup lang="ts">
import Alert from './Alert.vue'

defineProps<{
  title: string
  error: any
}>()
</script>

<template>
  <Alert type="error">
    <template #title>
      {{ title }}
    </template>
    <template #content>
      <pre class="whitespace-pre-wrap break-all">{{ String(error) }}</pre>
    </template>
  </Alert>
</template>


Review comment (suggestion):
```suggestion
defineProps<{
  title?: string
  error?: any
}>()
```

Code after:
<script setup lang="ts">
import Alert from './Alert.vue'

defineProps<{
  title?: string
  error?: any
}>()
</script>

<template>
  <Alert type="error">
    <template #title>
      {{ title }}
    </template>
    <template #content>
      <pre class="whitespace-pre-wrap break-all">{{ String(error) }}</pre>
    </template>
  </Alert>
</template>
Repository: moeru-ai/airi
File: packages/stage-ui/src/components/Scenes/VRM/Model.vue (Vue)

Code before:
<script setup lang="ts">
import type { VRMCore } from '@pixiv/three-vrm-core'
import type { AnimationClip } from 'three'

import { VRMUtils } from '@pixiv/three-vrm'
import { useVRM } from '@proj-airi/stage-ui/stores'
import { useLoop, useTresContext } from '@tresjs/core'
import { storeToRefs } from 'pinia'
import { AnimationMixer } from 'three'
import { onMounted, onUnmounted, ref, watch } from 'vue'

import { clipFromVRMAnimation, loadVRMAnimation, useBlink, useIdleEyeSaccades } from '../../../composables/vrm/animation'
import { loadVrm } from '../../../composables/vrm/core'
import { useVRMEmote } from '../../../composables/vrm/expression'

const props = defineProps<{
  model: string
  idleAnimation: string
  loadAnimations?: string[]
  paused: boolean
}>()

const emit = defineEmits<{
  (e: 'loadModelProgress', value: number): void
  (e: 'error', value: unknown): void
}>()

let disposeBeforeRenderLoop: (() => void | undefined)

const vrm = ref<VRMCore>()
const vrmAnimationMixer = ref<AnimationMixer>()

Review comment (suggestion):
```suggestion
import { useVRM } from '../../../stores'
```

Importing `stage-ui` itself inside `stage-ui` will have unexpected consequences. Let's use `../../../stores`

Code after:
<script setup lang="ts">
import type { VRMCore } from '@pixiv/three-vrm-core'
import type { AnimationClip } from 'three'

import { VRMUtils } from '@pixiv/three-vrm'
import { useVRM } from '../../../stores'
import { useLoop, useTresContext } from '@tresjs/core'
import { storeToRefs } from 'pinia'
import { AnimationMixer } from 'three'
import { onMounted, onUnmounted, ref, watch } from 'vue'

import { clipFromVRMAnimation, loadVRMAnimation, useBlink, useIdleEyeSaccades } from '../../../composables/vrm/animation'
import { loadVrm } from '../../../composables/vrm/core'
import { useVRMEmote } from '../../../composables/vrm/expression'

const props = defineProps<{
  model: string
  idleAnimation: string
  loadAnimations?: string[]
  paused: boolean
}>()

const emit = defineEmits<{
  (e: 'loadModelProgress', value: number): void
  (e: 'error', value: unknown): void
}>()

let disposeBeforeRenderLoop: (() => void | undefined)

const vrm = ref<VRMCore>()
const vrmAnimationMixer = ref<AnimationMixer>()
Repository: moeru-ai/airi
File: packages/stage-ui/src/composables/vrm/core.ts (TypeScript)

Code before:
  VRMUtils.combineSkeletons(_vrm.scene)

  // Disable frustum culling
  _vrm.scene.traverse((object: Object3D) => {
    object.frustumCulled = false
  })

  // Add look at quaternion proxy to the VRM; which is needed to play the look at animation
  if (options?.lookAt && _vrm.lookAt) {
    const lookAtQuatProxy = new VRMLookAtQuaternionProxy(_vrm.lookAt)
    lookAtQuatProxy.name = 'lookAtQuaternionProxy'
    _vrm.scene.add(lookAtQuatProxy)
  }

  // Add to scene
  if (options?.scene)
    options.scene.add(_vrm.scene)

  // Move the VRM model centre to the (0, 0, 0)
  const box = new Box3().setFromObject(_vrm.scene)
  const modelSize = new Vector3()
  const modelCenter = new Vector3()
  box.getSize(modelSize)
  box.getCenter(modelCenter)
  modelCenter.negate()
modelCenter.y -= modelSize.y / 8 // Adjust pivot to align chest with the origin

  // Set position
  if (options?.positionOffset) {
    _vrm.scene.position.set(
      modelCenter.x + options.positionOffset[0],
      modelCenter.y + options.positionOffset[1],
      modelCenter.z + options.positionOffset[2],
    )
  }
  else {
    _vrm.scene.position.set(modelCenter.x, modelCenter.y, modelCenter.z)
  }

  return {
    _vrm,
    modelCenter,
    modelSize,
  }
}


Review comment (suggestion):
```suggestion
  modelCenter.y -= modelSize.y / 8 // Adjust pivot to align chest with the origin
```

Code after:
  VRMUtils.combineSkeletons(_vrm.scene)

  // Disable frustum culling
  _vrm.scene.traverse((object: Object3D) => {
    object.frustumCulled = false
  })

  // Add look at quaternion proxy to the VRM; which is needed to play the look at animation
  if (options?.lookAt && _vrm.lookAt) {
    const lookAtQuatProxy = new VRMLookAtQuaternionProxy(_vrm.lookAt)
    lookAtQuatProxy.name = 'lookAtQuaternionProxy'
    _vrm.scene.add(lookAtQuatProxy)
  }

  // Add to scene
  if (options?.scene)
    options.scene.add(_vrm.scene)

  // Move the VRM model centre to the (0, 0, 0)
  const box = new Box3().setFromObject(_vrm.scene)
  const modelSize = new Vector3()
  const modelCenter = new Vector3()
  box.getSize(modelSize)
  box.getCenter(modelCenter)
  modelCenter.negate()
  modelCenter.y -= modelSize.y / 8 // Adjust pivot to align chest with the origin

  // Set position
  if (options?.positionOffset) {
    _vrm.scene.position.set(
      modelCenter.x + options.positionOffset[0],
      modelCenter.y + options.positionOffset[1],
      modelCenter.z + options.positionOffset[2],
    )
  }
  else {
    _vrm.scene.position.set(modelCenter.x, modelCenter.y, modelCenter.z)
  }

  return {
    _vrm,
    modelCenter,
    modelSize,
  }
}
Repository: moeru-ai/airi
File: packages/stage-ui/src/components/Scenarios/Settings/ModelSettings/Live2D.vue (Vue)

Code before:
        </div>
      </template>
    </FieldRange>
    <FieldRange v-model="position.y" as="div" :min="-100" :max="100" :step="1" :label="t('settings.live2d.scale-and-position.y')">
      <template #label>
        <div flex items-center>
          <div>{{ t('settings.live2d.scale-and-position.y') }}</div>
          <button px-2 text-xs outline-none title="Reset value to default" @click="() => position.y = 0">
            <div i-solar:forward-linear transform-scale-x--100 text="neutral-500 dark:neutral-400" />
          </button>
        </div>
      </template>
    </FieldRange>
  </Section>
  <Section
    :title="t('settings.live2d.focus.title')"
    icon="i-solar:eye-scan-bold-duotone"
    :class="[
      'rounded-xl',
      'bg-white/80  dark:bg-black/75',
      'backdrop-blur-lg',
    ]"
  >
    <Checkbox
      v-model="live2dDisableFocus"
      :label="t('settings.live2d.focus.disable-focus')"
    />
  </Section>
</template>


Review comment (suggestion):
```suggestion
      :label="t('settings.live2d.focus.button-disable.title')"
```

Code after:
        </div>
      </template>
    </FieldRange>
    <FieldRange v-model="position.y" as="div" :min="-100" :max="100" :step="1" :label="t('settings.live2d.scale-and-position.y')">
      <template #label>
        <div flex items-center>
          <div>{{ t('settings.live2d.scale-and-position.y') }}</div>
          <button px-2 text-xs outline-none title="Reset value to default" @click="() => position.y = 0">
            <div i-solar:forward-linear transform-scale-x--100 text="neutral-500 dark:neutral-400" />
          </button>
        </div>
      </template>
    </FieldRange>
  </Section>
  <Section
    :title="t('settings.live2d.focus.title')"
    icon="i-solar:eye-scan-bold-duotone"
    :class="[
      'rounded-xl',
      'bg-white/80  dark:bg-black/75',
      'backdrop-blur-lg',
    ]"
  >
    <Checkbox
      v-model="live2dDisableFocus"
      :label="t('settings.live2d.focus.button-disable.title')"
    />
  </Section>
</template>
Repository: moeru-ai/airi
File: packages/stage-ui/src/components/Scenarios/Providers/SpeechStreamingPlayground.vue (Vue)

Code before:
            'b-purple text-purple': chunk.reason === 'flush',
          }"
        >
          {{ chunk.words }} words,
          {{ chunk.reason }}
        </span>
      </div>
      <transition
        :css="false"
        @enter="(el) => animate(el, {
          opacity: [0, 1],
          translateX: [10, 0],
          duration: 200,
          ease: 'inOut',
        })"
      >
        <div
          v-if="speechGenerationIndex >= i"
          tag="div"
          flex="~ row items-center gap-1"
          text-sm
        >
          <div i-solar-check-circle-line-duotone />
          <div>Queued</div>
        </div>
      </transition>
    </div>
  </div>
</template>


Review comment (suggestion):
```suggestion
      <Transition
        :css="false"
        @enter="(el) => animate(el, {
          opacity: [0, 1],
          translateX: [10, 0],
          duration: 200,
          ease: 'inOut',
        })"
      >
        <div
          v-if="speechGenerationIndex >= i"
          tag="div"
          flex="~ row items-center gap-1"
          text-sm
        >
          <div i-solar-check-circle-line-duotone />
          <div>Queued</div>
        </div>
      </Transition>
```

Code after:
            'b-purple text-purple': chunk.reason === 'flush',
          }"
        >
          {{ chunk.words }} words,
          {{ chunk.reason }}
        </span>
      </div>
      <Transition
        :css="false"
        @enter="(el) => animate(el, {
          opacity: [0, 1],
          translateX: [10, 0],
          duration: 200,
          ease: 'inOut',
        })"
      >
        <div
          v-if="speechGenerationIndex >= i"
          tag="div"
          flex="~ row items-center gap-1"
          text-sm
        >
          <div i-solar-check-circle-line-duotone />
          <div>Queued</div>
        </div>
      </Transition>
    </div>
  </div>
</template>
Repository: moeru-ai/airi
File: packages/stage-ui/src/components/Scenes/VRM.vue (Vue)

Code before:
<script setup lang="ts">
import { TresCanvas } from '@tresjs/core'
import { useElementBounding } from '@vueuse/core'
import { storeToRefs } from 'pinia'
import { onMounted, ref, shallowRef, watch } from 'vue'

import * as THREE from 'three'

import { useVRM } from '../../stores'
import { OrbitControls, VRMModel } from '../Scenes'

const emit = defineEmits<{
  (e: 'loadModelProgress', value: number): void
  (e: 'error', value: unknown): void
}>()
const VRMContainerRef = ref<HTMLDivElement>()
const { width, height } = useElementBounding(VRMContainerRef)
const {
  selectedModel,
  cameraFOV,
  initialCameraPosition,
} = storeToRefs(useVRM())

const modelRef = ref<InstanceType<typeof VRMModel>>()

const camera = shallowRef(new THREE.PerspectiveCamera())

onMounted(() => {
  if (VRMContainerRef.value) {
    camera.value.aspect = width.value / height.value
    camera.value.fov = cameraFOV.value
    camera.value.position.set(
      initialCameraPosition.value.x,
      initialCameraPosition.value.y,
      initialCameraPosition.value.z,
    )
    camera.value.updateProjectionMatrix()
  }
})

watch(cameraFOV, (newFov) => {

Review comment (suggestion):
```suggestion
const vrmContainerRef = ref<HTMLDivElement>()
```

Code after:
<script setup lang="ts">
import { TresCanvas } from '@tresjs/core'
import { useElementBounding } from '@vueuse/core'
import { storeToRefs } from 'pinia'
import { onMounted, ref, shallowRef, watch } from 'vue'

import * as THREE from 'three'

import { useVRM } from '../../stores'
import { OrbitControls, VRMModel } from '../Scenes'

const emit = defineEmits<{
  (e: 'loadModelProgress', value: number): void
  (e: 'error', value: unknown): void
}>()
const vrmContainerRef = ref<HTMLDivElement>()
const { width, height } = useElementBounding(vrmContainerRef)
const {
  selectedModel,
  cameraFOV,
  initialCameraPosition,
} = storeToRefs(useVRM())

const modelRef = ref<InstanceType<typeof VRMModel>>()

const camera = shallowRef(new THREE.PerspectiveCamera())

onMounted(() => {
  if (vrmContainerRef.value) {
    camera.value.aspect = width.value / height.value
    camera.value.fov = cameraFOV.value
    camera.value.position.set(
      initialCameraPosition.value.x,
      initialCameraPosition.value.y,
      initialCameraPosition.value.z,
    )
    camera.value.updateProjectionMatrix()
  }
})

watch(cameraFOV, (newFov) => {
Repository: moeru-ai/airi
File: packages/stage-ui/src/components/Scenes/VRM.vue (Vue)

Code before:
import { storeToRefs } from 'pinia'
import { onMounted, ref, shallowRef, watch } from 'vue'

import * as THREE from 'three'

import { useVRM } from '../../stores'
import { OrbitControls, VRMModel } from '../Scenes'

const emit = defineEmits<{
  (e: 'loadModelProgress', value: number): void
  (e: 'error', value: unknown): void
}>()
const VRMContainerRef = ref<HTMLDivElement>()
const { width, height } = useElementBounding(VRMContainerRef)
const {
  selectedModel,
  cameraFOV,
  initialCameraPosition,
} = storeToRefs(useVRM())

const modelRef = ref<InstanceType<typeof VRMModel>>()

const camera = shallowRef(new THREE.PerspectiveCamera())

onMounted(() => {
  if (VRMContainerRef.value) {
    camera.value.aspect = width.value / height.value
    camera.value.fov = cameraFOV.value
    camera.value.position.set(
      initialCameraPosition.value.x,
      initialCameraPosition.value.y,
      initialCameraPosition.value.z,
    )
    camera.value.updateProjectionMatrix()
  }
})

watch(cameraFOV, (newFov) => {
  if (camera.value) {
    camera.value.fov = newFov
    camera.value.updateProjectionMatrix()
  }
})

// not sure if we need this
// watch([width, height], () => {
//   if (camera.value) {
//     camera.value.aspect = width.value / height.value
//     camera.value.updateProjectionMatrix()
//   }
// })

Review comment (suggestion):
```suggestion
  if (vrmContainerRef.value) {
```

Code after:
import { storeToRefs } from 'pinia'
import { onMounted, ref, shallowRef, watch } from 'vue'

import * as THREE from 'three'

import { useVRM } from '../../stores'
import { OrbitControls, VRMModel } from '../Scenes'

const emit = defineEmits<{
  (e: 'loadModelProgress', value: number): void
  (e: 'error', value: unknown): void
}>()
const vrmContainerRef = ref<HTMLDivElement>()
const { width, height } = useElementBounding(vrmContainerRef)
const {
  selectedModel,
  cameraFOV,
  initialCameraPosition,
} = storeToRefs(useVRM())

const modelRef = ref<InstanceType<typeof VRMModel>>()

const camera = shallowRef(new THREE.PerspectiveCamera())

onMounted(() => {
  if (vrmContainerRef.value) {
    camera.value.aspect = width.value / height.value
    camera.value.fov = cameraFOV.value
    camera.value.position.set(
      initialCameraPosition.value.x,
      initialCameraPosition.value.y,
      initialCameraPosition.value.z,
    )
    camera.value.updateProjectionMatrix()
  }
})

watch(cameraFOV, (newFov) => {
  if (camera.value) {
    camera.value.fov = newFov
    camera.value.updateProjectionMatrix()
  }
})

// not sure if we need this
// watch([width, height], () => {
//   if (camera.value) {
//     camera.value.aspect = width.value / height.value
//     camera.value.updateProjectionMatrix()
//   }
// })