Help with rotating objects around pivot point animation, react 3 fiber


I’m trying to create an animation where a bunch of objects in a group are rotated by some amount of degrees, triggered by user input. (rotating the container basically, like rotating a plate and all the objects are on the edge of the plate)

I’ve come up with this code where I offset the objects from their group and rotate the group with slerp. However, I have the issue that Slerp will take the shortest path when rotating so the objects won’t rotate in the same direction.

I’m wondering, is there an easier way to rotate a given amount of degrees without slerp? How can I dispatch a discrete animation with useFrame – say on keystroke rotate by 10 degrees – since it always is running? Should I use a boolean condition? I’m stumped lol. Thank you. I do like the smooth interpolation of slerp and would like to achieve that effect

export const Carousel = forwardRef((props, ref) => {
    const universe = useRef();

    const quaternion = new THREE.Quaternion();
  let xAxis = new THREE.Vector3(0, 1, 0);
  quaternion.setFromAxisAngle(xAxis, props.angle);

    useFrame(() => {
    universe.current.quaternion.slerp(quaternion, 0.01);
   return (
      <group position ={[0, 0, 0]}>
      <group ref={universe} position={[0, 0, -20]} 


i have never had to use quaternions just to rotate a plate, why not rotation.y?

universe.current.rotation.y = degreeInRadians

How can I dispatch a discrete animation with useFrame

threejs is fundamentally loop driven. your loop animates towards state. state comes in as props reactively, context, store-state, hooks, etc. your state contains the goal values, the where-to, never the interpolated in-between values, that’s what the loop is for.

function Carousel({ rotation }) {
  useFrame(() => {
    // This will animate towards "rotation"
    universe.current.rotation.y = THREE.MathUtils.lerp(

there are better ways to animate than lerp, i’d suggest you use damping:

Ahh – so I will get a smooth interpolation without slerp? Thank you. I will try that. I did try the example code you mentioned – I am getting an error that I cannot assign rotation a value because it’s read-only

in this following line I think

universe.current.rotation = THREE.MathUtils.lerp(

slerp, lerp, its the same. but i would use damping for quaternions as well: dampQ.

sorry, i meant

universe.current.rotation.y = THREE.MathUtils.lerp(

with damp it would be

useFrame((state, delta) => {
  dampE(universe.current.rotation, [0, rotation, 0], 0.1, delta)

the delta value makes certain that this will run independent of the device refresh rate, it will look the same on all devices, lerp/slerp won’t (at least not just like that).

This worked perfectly, thank you! I will try playing around with damp as well. All the best