Skip to content

useVRMExpressionManager

Manages VRM facial expressions with automatic crossfade blending between states, plus optional hold and decay timing.

import { useVRMModel } from 'three-vrm-utils/use-vrm-model'
import { useVRMExpressionManager } from 'three-vrm-utils/use-vrm-expression-manager'
import { useFrame } from '@react-three/fiber'
import { useEffect } from 'react'
function ExpressiveVRM({ url }: { url: string }) {
const [, vrm] = useVRMModel(url)
const { send, stop } = useVRMExpressionManager(vrm)
useEffect(() => {
// Simple: set expression to a value (crossfades in)
send({ happy: 1 })
// With timing: hold for 2s then decay over 0.2s
send({ surprised: { value: 1, hold: 2, decay: 0.2 } })
}, [send])
useFrame((_, delta) => {
vrm.update(delta)
})
return <primitive object={vrm.scene} />
}

Calling send() again crossfades from the current expression to the new one. Previous expressions decay out while new ones ramp in over blendTime.

send({ happy: 1 }) // happy ramps in over blendTime
send({ relaxed: 0.7 }) // happy decays out, relaxed ramps in (crossfade)
stop() // everything decays to neutral
OptionTypeDefaultDescription
blendTimenumber0.15Crossfade duration between expressions in seconds. Set to 0 for instant snapping.
const { send, stop } = useVRMExpressionManager(vrm, { blendTime: 0.3 })
PropertyTypeDescription
send(map: ExpressionMap) => voidSet one or more expressions (crossfades from previous)
stop() => voidDecay all active expressions to neutral over blendTime

Each key is a VRM expression preset name (e.g. happy, angry, sad, relaxed, surprised, aa, ih, ou, ee, oh).

Values can be:

  • number — set the expression to that value and hold indefinitely
  • { value, hold?, decay? } — set with optional timing
OptionTypeDefaultDescription
valuenumberExpression intensity (0-1)
holdnumberindefiniteSeconds to hold at full value
decaynumber0Seconds to fade to 0 after hold expires