threed-garden
Version:
ThreeD Garden: WebGL 3D Environment Interface for Next.JS React TypeScript Three.JS React-Three Physics, 2D Paper.JS; APIs: Apollo GraphQL, WordPress; CSS: Tailwind, Radix-UI; Libraries: FarmBot 3D; AI: OpenAI, DeepSeek
73 lines (63 loc) • 2.63 kB
JSX
/*
This file was generated by https://github.com/pmndrs/gltfjsx and then
customized manually. It uses drei's new useAnimations hook which extracts
all actions and sets up a THREE.AnimationMixer for it so that you don't have to.
All of the assets actions, action-names and clips are available in its output.
*/
import React, { useEffect, useState } from 'react'
import { useGLTF, useTexture, useAnimations } from '@react-three/drei'
import { a, useSpring } from '@react-spring/three'
export default function Model(props) {
// Fetch model and a separate texture
const { nodes, animations } = useGLTF('/assets/examples/stacy.glb')
const texture = useTexture('/assets/examples/stacy.jpg')
// Extract animation actions
const { ref, actions, names } = useAnimations(animations)
// Hover and animation-index states
const [hovered, setHovered] = useState(false)
const [index, setIndex] = useState(4)
// Animate the selection halo
const { color, scale } = useSpring({
scale: hovered ? [1.15, 1.15, 1] : [1, 1, 1],
color: hovered ? '#ff6d6d' : '#569AFF',
})
// Change cursor on hover-state
useEffect(() => void (document.body.style.cursor = hovered ? 'pointer' : 'auto'), [hovered])
// Change animation when the index changes
useEffect(() => {
// Reset and fade in animation after an index has been changed
actions[names[index]].reset().fadeIn(0.5).play()
// In the clean-up phase, fade it out
// (page route may have changed)
if (actions[names[index]]) {
return () => actions[names[index]].fadeOut(0.5)
}
return null
}, [index, actions, names])
return (
<group ref={ref} {...props} dispose={null}>
<group rotation={[Math.PI / 2, 0, 0]} scale={0.01}>
{/* actions */}
<primitive object={nodes.mixamorigHips} />
{/* model */}
<skinnedMesh
castShadow
receiveShadow
onPointerOver={() => setHovered(true)}
onPointerOut={() => setHovered(false)}
onClick={() => setIndex((index + 1) % names.length)}
geometry={nodes.stacy.geometry}
skeleton={nodes.stacy.skeleton}
rotation={[-Math.PI / 2, 0, 0]}
scale={100}>
<meshStandardMaterial map={texture} map-flipY={false} skinning />
</skinnedMesh>
</group>
{/* background circle */}
{/* <a.mesh receiveShadow position={[0, 1, -1]} scale={scale}>
<circleGeometry args={[1, 64]} />
<a.meshStandardMaterial color={color} />
</a.mesh> */}
</group>
)
}