Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
65 lines
2.2 KiB
TypeScript
65 lines
2.2 KiB
TypeScript
import { Canvas, useThree } from '@react-three/fiber';
|
|
import { OrbitControls, useGLTF, useAnimations } from '@react-three/drei';
|
|
import { useEffect, useState, useRef } from 'react';
|
|
|
|
function DuckModel({ onLoaded }: { onLoaded: () => void }) {
|
|
const character = useGLTF('/duck3D/Character_output.glb');
|
|
const animations = useGLTF('/duck3D/Meshy_Merged_Animations.glb');
|
|
const meshRef = useRef<any>(null);
|
|
const { actions } = useAnimations(animations.animations, meshRef);
|
|
|
|
useEffect(() => {
|
|
onLoaded();
|
|
}, [character, animations, onLoaded]);
|
|
|
|
useEffect(() => {
|
|
if (!actions) return;
|
|
const action = actions['Walking'];
|
|
if (!action) return;
|
|
action.reset();
|
|
action.setLoop(2201, Infinity);
|
|
action.clampWhenFinished = false;
|
|
action.fadeIn(0.4);
|
|
action.play();
|
|
}, [actions]);
|
|
|
|
return <primitive ref={meshRef} object={character.scene} position={[0, -0.2, 0]} scale={4.5} rotation={[-0.1, (10 * Math.PI) / 180, 0]} />;
|
|
}
|
|
|
|
function Camera() {
|
|
const { camera } = useThree();
|
|
const controlsRef = useRef<any>(null);
|
|
|
|
useEffect(() => {
|
|
if (controlsRef.current) {
|
|
controlsRef.current.target.set(0.3, 3.29, -0.4);
|
|
camera.position.set(2.89, 5.24, 7.38);
|
|
controlsRef.current.update();
|
|
}
|
|
}, [camera]);
|
|
|
|
return <OrbitControls ref={controlsRef} enabled={false} target={[0.3, 3.29, -0.4]} />;
|
|
}
|
|
|
|
export function DuckAvatar() {
|
|
const [isLoaded, setIsLoaded] = useState(false);
|
|
|
|
return (
|
|
<div
|
|
className="fixed top-12 md:top-auto md:bottom-0 left-1/2 -translate-x-1/2 w-[60vh] h-[75vh] overflow-visible z-1 pointer-events-none"
|
|
style={{ background: 'transparent', opacity: isLoaded ? 1 : 0 }}
|
|
>
|
|
<div className="w-full h-full pointer-events-none overflow-visible" style={{ background: 'transparent' }}>
|
|
<Canvas camera={{ position: [2.89, 5.24, 7.38], fov: 65, near: 0.1, far: 1000 }} style={{ background: 'transparent' }}>
|
|
<ambientLight intensity={1.5} />
|
|
<directionalLight position={[10, 10, 5]} intensity={2} />
|
|
<directionalLight position={[-10, -10, -5]} intensity={1} />
|
|
<pointLight position={[0, 5, 0]} intensity={1.5} />
|
|
<Camera />
|
|
<DuckModel onLoaded={() => setIsLoaded(true)} />
|
|
</Canvas>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|