diff --git a/README.md b/README.md index 50d607f..1ff6983 100644 --- a/README.md +++ b/README.md @@ -15,3 +15,8 @@ pnpm i ```shell pnpm dev ``` + +## Acknowledgements + +- [pixiv/ChatVRM](https://github.com/pixiv/ChatVRM) +- [josephrocca/ChatVRM-js: A JS conversion/adaptation of parts of the ChatVRM (TypeScript) code for standalone use in OpenCharacters and elsewhere](https://github.com/josephrocca/ChatVRM-js) diff --git a/README.zh-CN.md b/README.zh-CN.md index 2aabb70..3c38714 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -15,3 +15,8 @@ pnpm i ```shell pnpm dev ``` + +## Acknowledgements + +- [pixiv/ChatVRM](https://github.com/pixiv/ChatVRM) +- [josephrocca/ChatVRM-js: A JS conversion/adaptation of parts of the ChatVRM (TypeScript) code for standalone use in OpenCharacters and elsewhere](https://github.com/josephrocca/ChatVRM-js) diff --git a/cspell.config.yaml b/cspell.config.yaml index a7a3970..da369b0 100644 --- a/cspell.config.yaml +++ b/cspell.config.yaml @@ -54,6 +54,7 @@ words: - unhead - unocss - unplugin + - vrma - vueuse - xsai ignoreWords: [] diff --git a/packages/stage/package.json b/packages/stage/package.json index 5c4fadf..3346b0e 100644 --- a/packages/stage/package.json +++ b/packages/stage/package.json @@ -31,7 +31,9 @@ "@pixi/sprite": "6", "@pixi/ticker": "^6.5.10", "@pixi/utils": "6", - "@pixiv/three-vrm": "^3.2.0", + "@pixiv/three-vrm": "^3.3.0", + "@pixiv/three-vrm-animation": "^3.3.0", + "@pixiv/three-vrm-core": "^3.3.0", "@tresjs/cientos": "^4.0.3", "@tresjs/core": "^4.3.1", "@types/yauzl": "^2.10.3", diff --git a/packages/stage/public/assets/vrm/animations/idle_loop.vrma b/packages/stage/public/assets/vrm/animations/idle_loop.vrma new file mode 100644 index 0000000..26b28f4 Binary files /dev/null and b/packages/stage/public/assets/vrm/animations/idle_loop.vrma differ diff --git a/packages/stage/src/components/MainStage.vue b/packages/stage/src/components/MainStage.vue index a2b4193..a0e6c82 100644 --- a/packages/stage/src/components/MainStage.vue +++ b/packages/stage/src/components/MainStage.vue @@ -324,7 +324,8 @@ onUnmounted(() => { /> diff --git a/packages/stage/src/components/ThreeDScene.vue b/packages/stage/src/components/ThreeDScene.vue index 8f57df8..2555fc6 100644 --- a/packages/stage/src/components/ThreeDScene.vue +++ b/packages/stage/src/components/ThreeDScene.vue @@ -8,6 +8,7 @@ import VRMModel from './VRMModel.vue' const props = defineProps<{ model: string + idleAnimation: string }>() const emit = defineEmits<{ @@ -15,12 +16,12 @@ const emit = defineEmits<{ (e: 'error', value: unknown): void }>() -const cameraPositionX = ref(0) -const cameraPositionY = ref(0.1) -const cameraPositionZ = ref(-1.5) -const vrmModelPositionX = ref(0) +const cameraPositionX = ref(-0.17) +const cameraPositionY = ref(0) +const cameraPositionZ = ref(-1) +const vrmModelPositionX = ref(-0.18) const vrmModelPositionY = ref(-1.4) -const vrmModelPositionZ = ref(-0.3) +const vrmModelPositionZ = ref(-0.24) diff --git a/packages/stage/src/components/VRMModel.vue b/packages/stage/src/components/VRMModel.vue index 91160c8..7d08778 100644 --- a/packages/stage/src/components/VRMModel.vue +++ b/packages/stage/src/components/VRMModel.vue @@ -1,11 +1,14 @@ diff --git a/packages/stage/src/composables/vrm/animation.ts b/packages/stage/src/composables/vrm/animation.ts new file mode 100644 index 0000000..74d8442 --- /dev/null +++ b/packages/stage/src/composables/vrm/animation.ts @@ -0,0 +1,40 @@ +import type { VRMAnimation } from '@pixiv/three-vrm-animation' +import type { VRMCore } from '@pixiv/three-vrm-core' +import { createVRMAnimationClip } from '@pixiv/three-vrm-animation' +import { useVRMLoader } from './loader' + +export interface GLTFUserdata extends Record { + vrmAnimations: VRMAnimation[] +} + +export async function loadVRMAnimation(url: string) { + const loader = useVRMLoader() + + // load VRM Animation .vrma file + const gltf = await loader.loadAsync(url) + + const userData = gltf.userData as GLTFUserdata + if (!userData.vrmAnimations) { + console.warn('No VRM animations found in the .vrma file') + return + } + if (userData.vrmAnimations.length === 0) { + console.warn('No VRM animations found in the .vrma file') + return + } + + return userData.vrmAnimations[0] +} + +export async function clipFromVRMAnimation(vrm?: VRMCore, animation?: VRMAnimation) { + if (!vrm) { + console.warn('No VRM found') + return + } + if (!animation) { + return + } + + // create animation clip + return createVRMAnimationClip(animation, vrm) +} diff --git a/packages/stage/src/composables/vrm/core.ts b/packages/stage/src/composables/vrm/core.ts new file mode 100644 index 0000000..72e3ecb --- /dev/null +++ b/packages/stage/src/composables/vrm/core.ts @@ -0,0 +1,52 @@ +import type { Object3D, Scene } from 'three' +import { type VRMCore, VRMUtils } from '@pixiv/three-vrm' + +import { VRMLookAtQuaternionProxy } from '@pixiv/three-vrm-animation' +import { useVRMLoader } from './loader' + +interface GLTFUserdata extends Record { + vrmCore?: VRMCore +} + +export async function loadVrm(model: string, options?: { + position?: [number, number, number] + scene?: Scene + lookAt?: boolean + onProgress?: (progress: ProgressEvent) => void | Promise +}): Promise { + const loader = useVRMLoader() + const gltf = await loader.loadAsync(model, progress => options?.onProgress?.(progress)) + + const userData = gltf.userData as GLTFUserdata + if (!userData.vrm) { + return + } + + const _vrm = userData.vrm + + // calling these functions greatly improves the performance + VRMUtils.removeUnnecessaryVertices(_vrm.scene) + 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) + + // Set position + if (options?.position) + _vrm.scene.position.set(...options.position) + + return _vrm +} diff --git a/packages/stage/src/composables/vrm/loader.ts b/packages/stage/src/composables/vrm/loader.ts new file mode 100644 index 0000000..22b552d --- /dev/null +++ b/packages/stage/src/composables/vrm/loader.ts @@ -0,0 +1,19 @@ +import { VRMLoaderPlugin } from '@pixiv/three-vrm' +import { VRMAnimationLoaderPlugin } from '@pixiv/three-vrm-animation' +import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js' + +let loader: GLTFLoader + +export function useVRMLoader() { + if (loader) { + return loader + } + + loader = new GLTFLoader() + + loader.crossOrigin = 'anonymous' + loader.register(parser => new VRMLoaderPlugin(parser)) + loader.register(parser => new VRMAnimationLoaderPlugin(parser)) + + return loader +} diff --git a/packages/stage/src/libs/audio/manager.ts b/packages/stage/src/libs/audio/manager.ts new file mode 100644 index 0000000..7469c3f --- /dev/null +++ b/packages/stage/src/libs/audio/manager.ts @@ -0,0 +1,87 @@ +export interface AudioManagerType { + audioContext: AudioContext + analyser: AnalyserNode + dataBuffer: Float32Array + frameId: number | null + onVolumeChange?: (volume: number) => void +} + +export function createAudioManager(): AudioManagerType { + const audioContext = new AudioContext() + const analyser = audioContext.createAnalyser() + const dataBuffer = new Float32Array(2048) + + // Connect analyser to destination + analyser.connect(audioContext.destination) + + return { + audioContext, + analyser, + dataBuffer, + frameId: null, + onVolumeChange: undefined, + } +} + +function calculateVolume(manager: AudioManagerType): number { + manager.analyser.getFloatTimeDomainData(manager.dataBuffer) + + // Find peak volume + let volume = 0.0 + for (let i = 0; i < manager.dataBuffer.length; i++) { + volume = Math.max(volume, Math.abs(manager.dataBuffer[i])) + } + + // Apply sigmoid normalization (from pixiv implementation) + volume = 1 / (1 + Math.exp(-45 * volume + 5)) + return volume < 0.1 ? 0 : volume +} + +function updateFrame(manager: AudioManagerType) { + if (manager.onVolumeChange) { + manager.onVolumeChange(calculateVolume(manager)) + } + manager.frameId = requestAnimationFrame(() => updateFrame(manager)) +} + +export async function playAudio(manager: AudioManagerType, source: ArrayBuffer | string): Promise { + try { + const buffer = typeof source === 'string' + ? await (await fetch(source)).arrayBuffer() + : source + + const audioBuffer = await manager.audioContext.decodeAudioData(buffer) + const bufferSource = manager.audioContext.createBufferSource() + + bufferSource.buffer = audioBuffer + bufferSource.connect(manager.analyser) + bufferSource.start() + + return new Promise((resolve) => { + bufferSource.onended = () => resolve() + }) + } + catch (error) { + console.error('Error playing audio:', error) + throw error + } +} + +export function startVolumeTracking(manager: AudioManagerType, callback: (volume: number) => void) { + manager.onVolumeChange = callback + manager.audioContext.resume() + updateFrame(manager) +} + +export function stopVolumeTracking(manager: AudioManagerType) { + if (manager.frameId) { + cancelAnimationFrame(manager.frameId) + manager.frameId = null + } + manager.onVolumeChange = undefined +} + +export function disposeAudioManager(manager: AudioManagerType) { + stopVolumeTracking(manager) + manager.audioContext.close() +} diff --git a/packages/stage/src/stores/llm.ts b/packages/stage/src/stores/llm.ts index c16837c..3776128 100644 --- a/packages/stage/src/stores/llm.ts +++ b/packages/stage/src/stores/llm.ts @@ -20,10 +20,7 @@ export const useLLM = defineStore('llm', () => { async function models(apiUrl: string, apiKey: string) { if (apiUrl === '') { - return { - data: [], - object: '', - } + return [] } try { @@ -34,10 +31,7 @@ export const useLLM = defineStore('llm', () => { } catch (err) { if (String(err).includes(`Failed to construct 'URL': Invalid URL`)) { - return { - data: [], - object: '', - } + return [] } throw err diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 089bf70..af9ae68 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -142,8 +142,14 @@ importers: specifier: '6' version: 6.5.10(@pixi/constants@6.5.10)(@pixi/settings@6.5.10(@pixi/constants@6.5.10)) '@pixiv/three-vrm': - specifier: ^3.2.0 - version: 3.2.0(three@0.171.0) + specifier: ^3.3.0 + version: 3.3.0(three@0.171.0) + '@pixiv/three-vrm-animation': + specifier: ^3.3.0 + version: 3.3.0(three@0.171.0) + '@pixiv/three-vrm-core': + specifier: ^3.3.0 + version: 3.3.0(three@0.171.0) '@tresjs/cientos': specifier: ^4.0.3 version: 4.0.3(@tresjs/core@4.3.1(three@0.171.0)(vue@3.5.13(typescript@5.7.2)))(@types/three@0.170.0)(react@18.3.1)(three@0.171.0)(vue@3.5.13(typescript@5.7.2)) @@ -1898,61 +1904,72 @@ packages: '@pixi/constants': 6.5.10 '@pixi/settings': 6.5.10 - '@pixiv/three-vrm-core@3.2.0': - resolution: {integrity: sha512-S/vEMSouVsbS7yv+PToK+r6UOWm0uR6d3djPOVSeGZKXbXjoNWZc5btjVWL+FAE1/rtdxXO9cMw0kBvI43Rujw==} + '@pixiv/three-vrm-animation@3.3.0': + resolution: {integrity: sha512-hv+Wq+4BVYZMw4g1IIOPqMyVewi+5gt9BO5T8STdd/M93dJnrwV1TTRhWhhRbwWVWYpKKX91dDrmjXJK5tKcJQ==} + peerDependencies: + three: '>=0.137' + + '@pixiv/three-vrm-core@3.3.0': + resolution: {integrity: sha512-AeeuErYF+jxhqJvoBuuc6pqqcegZMSgkLLE+huMHGHasMuHjQt2RAslcANLfpHLn65WEN4GmCtqBw2IWrxFiBQ==} peerDependencies: three: '>=0.137' - '@pixiv/three-vrm-materials-hdr-emissive-multiplier@3.2.0': - resolution: {integrity: sha512-3Ai1ENdNiVnsxfzzXSKDCyT+w6awY7sHjoX6fKKnQ9tn2WGhxY596VUGDp/WyGDY2BM4NkSCUVd6qSGNEeEX6g==} + '@pixiv/three-vrm-materials-hdr-emissive-multiplier@3.3.0': + resolution: {integrity: sha512-aiCAkkZtT4/RGBO75DNEqeIWjdbEg//UUU+uYls2cnNucGa6td9zFXMkQ2S7yj+38/DFmKAvOSBWKyI6Q6e7EQ==} peerDependencies: three: '>=0.137' - '@pixiv/three-vrm-materials-mtoon@3.2.0': - resolution: {integrity: sha512-wZollYD+cnTCdCJyrSuIGC1zVqXrZl2zWEzzwZ0+955/+UUltxYAHdFmSXpoChYNX89FFiIzIdfoARdYHMqNzw==} + '@pixiv/three-vrm-materials-mtoon@3.3.0': + resolution: {integrity: sha512-DvUeFidvY74fau/L+Lhe5sxvC5ri5eHK7SF700eYosJIWvDY/KgVkCjc3jCNqrAOp0OBGGCYjcvRDh23eVUO0Q==} peerDependencies: three: '>=0.137' - '@pixiv/three-vrm-materials-v0compat@3.2.0': - resolution: {integrity: sha512-z1qjQUjqTWWE7f/7vm2QzluL7e8fcSi/q6RMjpmsXQurfXdH06j43IWn5Lp8E9O16ZHbKw9HqBN8YkBv1qpgmg==} + '@pixiv/three-vrm-materials-v0compat@3.3.0': + resolution: {integrity: sha512-Ot0sj5Hfacw4258TDBFXOlWvI35B9YLW1wJ6WnqUZdlQd9t7dzD0o0NommOofVn40bRmIuI5Bxd5N9j0WxBxzg==} peerDependencies: three: '>=0.137' - '@pixiv/three-vrm-node-constraint@3.2.0': - resolution: {integrity: sha512-NQMD3KQJx2i6CEGnabcOdeS8/m0KUrvOp4N4iEdFM0LRd/34zmasHBqLROlhFMG7tGan858wZ1HqyWnKOIc6Rw==} + '@pixiv/three-vrm-node-constraint@3.3.0': + resolution: {integrity: sha512-XvbS1sFJsuCfnboxEKhV2NltT929k3/VSYkQLRvw+uz6oVPUJHZ3w6cK8E6pvD9WKuBefDf+AQZQpn5PCRO25w==} peerDependencies: three: '>=0.137' - '@pixiv/three-vrm-springbone@3.2.0': - resolution: {integrity: sha512-kMdHQLgHvhwNj/5WAPh6n+Q/Vva+9OgMFAzBtILoMKxfusS/LyDc7Du2KUaHU8huyB/ucvHSEan0rTEH2mz1dQ==} + '@pixiv/three-vrm-springbone@3.3.0': + resolution: {integrity: sha512-aLzRXJukck7G8g/lm2Asob1N0QPjgYGoGU4YA9IgpdBFIz07S3CNDww/Lv/wmLJahyZqQCdJvghSr2X5yG8EtQ==} peerDependencies: three: '>=0.137' - '@pixiv/three-vrm@3.2.0': - resolution: {integrity: sha512-M/t9xRK3v0SYsY1G4S3MMcQimovrQQBn4rcM+Ffh3z/gZTOGeivfRuGWhjZhxWY+ACoZ9X8HcpdvGbNsTVPrjQ==} + '@pixiv/three-vrm@3.3.0': + resolution: {integrity: sha512-zPr3di6BYeZzhMf3WOTR5uG/o88ZtLzUOar6n2VtTukY8IKX05rbBIoAwcjqgxXA7kn+CEverKN1tQXuYQAHKw==} peerDependencies: three: '>=0.137' - '@pixiv/types-vrm-0.0@3.2.0': - resolution: {integrity: sha512-hxj3Z1V8KqEfeg11+6Q0groz7Rdpg/WL0PsoEFvPY1U06QD2SZFIdxLsSh2yRfMiwL1DhZJi614PoaHMaMiVhQ==} + '@pixiv/types-vrm-0.0@3.3.0': + resolution: {integrity: sha512-3AC+hR24O9yEMxoKkGiEVvj8zydh/poy5ZR6FieyvbRsKTJ/+Z8WJgTKnO7hJHkvPOntYznhsWJqjj/YG9kTLw==} + + '@pixiv/types-vrmc-materials-hdr-emissive-multiplier-1.0@3.3.0': + resolution: {integrity: sha512-Q6PCgnt0Kl5v+DI8VAueJ4qyTgQjf186SpWa91m7ZTPIX7hsdOeXly7cO8n64UBnEgihcgWoBS8mhMOLbHBxVg==} + + '@pixiv/types-vrmc-materials-mtoon-1.0@3.3.0': + resolution: {integrity: sha512-I0tJIMbs6yaHoMu6cw/bZxABk1kieWKv0Gu6JhECfN8IAo+WM0sYPOYMfzEkbxulpDUA8JIo0Kfn5s1B2Maf2A==} - '@pixiv/types-vrmc-materials-hdr-emissive-multiplier-1.0@3.2.0': - resolution: {integrity: sha512-xWiWtUP7IdVAT4JFjSD797TaX1fD38TwBucahYjT8Yq2b20frRQJ+/FrCG1cJ83Ja02PDQGtLY1VKy4lZ6c4Xg==} + '@pixiv/types-vrmc-node-constraint-1.0@3.3.0': + resolution: {integrity: sha512-y6Ae2OFZQcY/ymxJqNT6lAT8Jo5kdDVfDtY2UvjtTlQ5tE0IbUv7HaBXVIX8CHurUWCy0kyV51iwSQ1Sdbw0bA==} - '@pixiv/types-vrmc-materials-mtoon-1.0@3.2.0': - resolution: {integrity: sha512-p6sWf6uzce3cSc8KiStSyB33GPwDEYPFjRxDKNpepe64i9wuXVqdtJNvh0WOWrb85VLxOfq78XAWeJIcdUF2Ww==} + '@pixiv/types-vrmc-springbone-1.0@3.3.0': + resolution: {integrity: sha512-IjyV9QyxcyohIji5AegC4OS2VMsSKEDA+1ddq39KBPtTPtjvSjGU7ppvNBrWXYhyX0s0OCOsdqM0SmTCZVp/kw==} - '@pixiv/types-vrmc-node-constraint-1.0@3.2.0': - resolution: {integrity: sha512-wZT86mIHDBV7GefnsdsEGwT6IDxZISNHhbaCAjmoyZNZz+mO/J65WOrdbiMSlTgFXxyiBVge7h4WplLMsZCuhA==} + '@pixiv/types-vrmc-springbone-extended-collider-1.0@3.3.0': + resolution: {integrity: sha512-5iBqq3S1MsOtKj5XVVbmx0z4UKO2muUSkamzI+Y2pErQsJyssu9SZBewPyC+aFG8XPk7wUbenQ5MxWHWOPFnFw==} - '@pixiv/types-vrmc-springbone-1.0@3.2.0': - resolution: {integrity: sha512-ifnnbtGQiVTJF51MRhNPGfpdZMePBlEKDpOJe83n0S0XmVtHahbspWelGxiecDbPfYUMElqpIBhnDZmai4fT5Q==} + '@pixiv/types-vrmc-vrm-1.0@2.0.3': + resolution: {integrity: sha512-RMP34Bk1qLFQv/CRB1Zqvn2qMFfWQfP2Hms5QrrfoBsW9XroZdEe0zPLNbGmUPYh4F7VtBb+B7+RCuymRtpehA==} - '@pixiv/types-vrmc-springbone-extended-collider-1.0@3.2.0': - resolution: {integrity: sha512-tImS5zKDMT9mliAyAaUmjs9susVj+mJiV8ZK2G2EOcchkt0SlD+kcrfpJPFxng5zfux/EFpIHUbXRFL9wqUOrQ==} + '@pixiv/types-vrmc-vrm-1.0@3.3.0': + resolution: {integrity: sha512-4JJizAfGFpyyL+IGMv22z5ORqJ2M3sFgYK0ZRF/ZjOmG8aaQHqh9zFx5KYXdudbT3N95Qo+Nl8/nLN5pwMFEoA==} - '@pixiv/types-vrmc-vrm-1.0@3.2.0': - resolution: {integrity: sha512-XvqfRK90DIQl+6PxqIi0svEmjilFzpOOOdzGR6zh0tNV0yBV4cemLSs9v6BouDMtPt4aZ69dQR2ApA8VMbaV4w==} + '@pixiv/types-vrmc-vrm-animation-1.0@3.3.0': + resolution: {integrity: sha512-jgmiBPldGmrWbn0EUMt51bb8cSZqBw43bUYHcQfTar70OyVC1h25aV1B34nTNzl1IDPX2QnV2FdOPASpRtRYAA==} '@pkgr/core@0.1.0': resolution: {integrity: sha512-Zwq5OCzuwJC2jwqmpEQt7Ds1DTi6BWSwoGkbb1n9pO3hzb35BoJELx7c0T23iDkBGkh2e7tvOtjF3tr3OaQHDQ==} @@ -8350,64 +8367,77 @@ snapshots: eventemitter3: 3.1.2 url: 0.11.4 - '@pixiv/three-vrm-core@3.2.0(three@0.171.0)': + '@pixiv/three-vrm-animation@3.3.0(three@0.171.0)': dependencies: - '@pixiv/types-vrm-0.0': 3.2.0 - '@pixiv/types-vrmc-vrm-1.0': 3.2.0 + '@pixiv/three-vrm-core': 3.3.0(three@0.171.0) + '@pixiv/types-vrmc-vrm-1.0': 3.3.0 + '@pixiv/types-vrmc-vrm-animation-1.0': 3.3.0 three: 0.171.0 - '@pixiv/three-vrm-materials-hdr-emissive-multiplier@3.2.0(three@0.171.0)': + '@pixiv/three-vrm-core@3.3.0(three@0.171.0)': dependencies: - '@pixiv/types-vrmc-materials-hdr-emissive-multiplier-1.0': 3.2.0 + '@pixiv/types-vrm-0.0': 3.3.0 + '@pixiv/types-vrmc-vrm-1.0': 3.3.0 three: 0.171.0 - '@pixiv/three-vrm-materials-mtoon@3.2.0(three@0.171.0)': + '@pixiv/three-vrm-materials-hdr-emissive-multiplier@3.3.0(three@0.171.0)': dependencies: - '@pixiv/types-vrm-0.0': 3.2.0 - '@pixiv/types-vrmc-materials-mtoon-1.0': 3.2.0 + '@pixiv/types-vrmc-materials-hdr-emissive-multiplier-1.0': 3.3.0 three: 0.171.0 - '@pixiv/three-vrm-materials-v0compat@3.2.0(three@0.171.0)': + '@pixiv/three-vrm-materials-mtoon@3.3.0(three@0.171.0)': dependencies: - '@pixiv/types-vrm-0.0': 3.2.0 - '@pixiv/types-vrmc-materials-mtoon-1.0': 3.2.0 + '@pixiv/types-vrm-0.0': 3.3.0 + '@pixiv/types-vrmc-materials-mtoon-1.0': 3.3.0 three: 0.171.0 - '@pixiv/three-vrm-node-constraint@3.2.0(three@0.171.0)': + '@pixiv/three-vrm-materials-v0compat@3.3.0(three@0.171.0)': dependencies: - '@pixiv/types-vrmc-node-constraint-1.0': 3.2.0 + '@pixiv/types-vrm-0.0': 3.3.0 + '@pixiv/types-vrmc-materials-mtoon-1.0': 3.3.0 three: 0.171.0 - '@pixiv/three-vrm-springbone@3.2.0(three@0.171.0)': + '@pixiv/three-vrm-node-constraint@3.3.0(three@0.171.0)': dependencies: - '@pixiv/types-vrm-0.0': 3.2.0 - '@pixiv/types-vrmc-springbone-1.0': 3.2.0 - '@pixiv/types-vrmc-springbone-extended-collider-1.0': 3.2.0 + '@pixiv/types-vrmc-node-constraint-1.0': 3.3.0 three: 0.171.0 - '@pixiv/three-vrm@3.2.0(three@0.171.0)': + '@pixiv/three-vrm-springbone@3.3.0(three@0.171.0)': dependencies: - '@pixiv/three-vrm-core': 3.2.0(three@0.171.0) - '@pixiv/three-vrm-materials-hdr-emissive-multiplier': 3.2.0(three@0.171.0) - '@pixiv/three-vrm-materials-mtoon': 3.2.0(three@0.171.0) - '@pixiv/three-vrm-materials-v0compat': 3.2.0(three@0.171.0) - '@pixiv/three-vrm-node-constraint': 3.2.0(three@0.171.0) - '@pixiv/three-vrm-springbone': 3.2.0(three@0.171.0) + '@pixiv/types-vrm-0.0': 3.3.0 + '@pixiv/types-vrmc-springbone-1.0': 3.3.0 + '@pixiv/types-vrmc-springbone-extended-collider-1.0': 3.3.0 three: 0.171.0 - '@pixiv/types-vrm-0.0@3.2.0': {} + '@pixiv/three-vrm@3.3.0(three@0.171.0)': + dependencies: + '@pixiv/three-vrm-core': 3.3.0(three@0.171.0) + '@pixiv/three-vrm-materials-hdr-emissive-multiplier': 3.3.0(three@0.171.0) + '@pixiv/three-vrm-materials-mtoon': 3.3.0(three@0.171.0) + '@pixiv/three-vrm-materials-v0compat': 3.3.0(three@0.171.0) + '@pixiv/three-vrm-node-constraint': 3.3.0(three@0.171.0) + '@pixiv/three-vrm-springbone': 3.3.0(three@0.171.0) + three: 0.171.0 + + '@pixiv/types-vrm-0.0@3.3.0': {} - '@pixiv/types-vrmc-materials-hdr-emissive-multiplier-1.0@3.2.0': {} + '@pixiv/types-vrmc-materials-hdr-emissive-multiplier-1.0@3.3.0': {} - '@pixiv/types-vrmc-materials-mtoon-1.0@3.2.0': {} + '@pixiv/types-vrmc-materials-mtoon-1.0@3.3.0': {} - '@pixiv/types-vrmc-node-constraint-1.0@3.2.0': {} + '@pixiv/types-vrmc-node-constraint-1.0@3.3.0': {} - '@pixiv/types-vrmc-springbone-1.0@3.2.0': {} + '@pixiv/types-vrmc-springbone-1.0@3.3.0': {} - '@pixiv/types-vrmc-springbone-extended-collider-1.0@3.2.0': {} + '@pixiv/types-vrmc-springbone-extended-collider-1.0@3.3.0': {} - '@pixiv/types-vrmc-vrm-1.0@3.2.0': {} + '@pixiv/types-vrmc-vrm-1.0@2.0.3': {} + + '@pixiv/types-vrmc-vrm-1.0@3.3.0': {} + + '@pixiv/types-vrmc-vrm-animation-1.0@3.3.0': + dependencies: + '@pixiv/types-vrmc-vrm-1.0': 2.0.3 '@pkgr/core@0.1.0': {}