diff --git a/min-react-2/index.html b/min-react-2/index.html new file mode 100644 index 000000000..a3d638f59 --- /dev/null +++ b/min-react-2/index.html @@ -0,0 +1,15 @@ + + + + + + VRM Animation Preview + + + +
+ + + diff --git a/min-react-2/package.json b/min-react-2/package.json new file mode 100644 index 000000000..eb99a0158 --- /dev/null +++ b/min-react-2/package.json @@ -0,0 +1,26 @@ +{ + "name": "min-react-vrm", + "version": "1.0.0", + "description": "Minimal VRM Animation Player", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview" + }, + "dependencies": { + "@pixiv/three-vrm": "^3.4.4", + "@pixiv/three-vrm-animation": "^3.4.4", + "@react-three/drei": "^10.7.7", + "@react-three/fiber": "^9.4.0", + "react": "^19.0.0", + "react-dom": "^19.0.0", + "three": "^0.181.2" + }, + "devDependencies": { + "@types/react": "^19.0.0", + "@types/react-dom": "^19.0.0", + "@vitejs/plugin-react": "^4.3.4", + "vite": "^6.0.1" + } +} diff --git a/min-react-2/public/ai.vrm b/min-react-2/public/ai.vrm new file mode 100644 index 000000000..d8fb84c00 Binary files /dev/null and b/min-react-2/public/ai.vrm differ diff --git a/min-react-2/public/idle.vrma b/min-react-2/public/idle.vrma new file mode 100644 index 000000000..fbb400bb5 Binary files /dev/null and b/min-react-2/public/idle.vrma differ diff --git a/min-react-2/public/run.vrma b/min-react-2/public/run.vrma new file mode 100644 index 000000000..242c889c8 Binary files /dev/null and b/min-react-2/public/run.vrma differ diff --git a/min-react-2/public/sky.vrma b/min-react-2/public/sky.vrma new file mode 100644 index 000000000..5cd32d27d Binary files /dev/null and b/min-react-2/public/sky.vrma differ diff --git a/min-react-2/src/App.jsx b/min-react-2/src/App.jsx new file mode 100644 index 000000000..a4a4b2de9 --- /dev/null +++ b/min-react-2/src/App.jsx @@ -0,0 +1,60 @@ +import React, { useEffect, useRef } from 'react'; +import { Canvas, useFrame, useLoader } from '@react-three/fiber'; +import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'; +import { VRMLoaderPlugin, VRMUtils } from '@pixiv/three-vrm'; +import { createVRMAnimationClip, VRMAnimationLoaderPlugin } from '@pixiv/three-vrm-animation'; +import { AnimationMixer, GridHelper, AxesHelper } from 'three'; +import { OrbitControls } from '@react-three/drei'; + +const VRM_URL = '/ai.vrm'; +const VRMA_URL = '/idle.vrma'; + +function Avatar() { + const mixerRef = useRef(null); + const vrmRef = useRef(null); + const gltf = useLoader(GLTFLoader, VRM_URL, (loader) => { + loader.register((parser) => new VRMLoaderPlugin(parser)); + }); + + const vrma = useLoader(GLTFLoader, VRMA_URL, (loader) => { + loader.register((parser) => new VRMAnimationLoaderPlugin(parser)); + }); + + useEffect(() => { + const vrm = gltf.userData.vrm; + vrmRef.current = vrm; + VRMUtils.removeUnnecessaryJoints(vrm.scene); + vrm.humanoid.resetPose(); + vrm.scene.rotation.y = Math.PI; + if (vrma.userData.vrmAnimations && vrma.userData.vrmAnimations.length > 0) { + const clip = createVRMAnimationClip(vrma.userData.vrmAnimations[0], vrm); + mixerRef.current = new AnimationMixer(vrm.scene); + mixerRef.current.clipAction(clip).play(); + } + }, [gltf, vrma]); + + useFrame((state, delta) => { + if (mixerRef.current) mixerRef.current.update(delta); + if (vrmRef.current) vrmRef.current.update(delta); + }); + + return ; +} + +export default function App() { + return ( +
+ + + + + + + + + + + +
+ ); +} diff --git a/min-react-2/src/main.jsx b/min-react-2/src/main.jsx new file mode 100644 index 000000000..1943cc824 --- /dev/null +++ b/min-react-2/src/main.jsx @@ -0,0 +1,9 @@ +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App' + +ReactDOM.createRoot(document.getElementById('root')).render( + + + , +) diff --git a/min-react-2/vite.config.ts b/min-react-2/vite.config.ts new file mode 100644 index 000000000..9ffcc6757 --- /dev/null +++ b/min-react-2/vite.config.ts @@ -0,0 +1,6 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' + +export default defineConfig({ + plugins: [react()], +})