React-Three-Fiber use-gesture to move the camera
Disclaimer: This article is from 2020. Please refer to newer articles about R3F since a lot of things changed.
In this tutorial you gonna learn how to bind gesture inputs from use-gesture to react-three-fiber. It wasn’t clear for me at first, so I thought I’ld make a simple tutorial about it. It’s originally from an example by Paul.

We are gonna using a custom camera. The reason behind this is to animate the camera. If you want to move objects with gestures, you don’t need to separate the camera from the canvas.
Instead of
<Canvas camera ...>
we can use
After stripping down the code a lil bit, it should look like this:
Next we are going to bind user gestures to our scene with react-use-gesture. Install
npm install react-use-gesture
and
npm install @react-spring/three
use-gesture for the input and react-spring for the animating of object. In this case it’s the camera. To keep things simple, create a new file named scroll.js and import both librarys like this.
import { useSpring, config } from “@react-spring/core”;import { useGesture } from “react-use-gesture”;
We also need
import { useCallback, useEffect } from “react”;
useCallBack and useEffect are simply hooks. Further reading: https://reactjs.org/docs/hooks-reference.html
We are not only gonna bind the wheel event, but also the drag event to make it mobile friendly. After that we bind it to the domTarget, which is the canvas. Usually gestures are bound to an object (e.g. for click events), but we don’t want that here. The final code for the Scroll.js looks like this:
Oh yeah, I forgot to mention that clamp is a super important and cool feature. We don’t need it in the infinite scene example, but it clamps two numbers and returns it. It’s like two if statements.
Next, import
import { a } from “@react-spring/three”;import Scroll from “./Scroll”;
to the App.js. We are binding a for the camera.
Inside our Camera function, create a constant,
const [y] = Scroll([-100, 100], { domTarget: window });
assign it to the position of the camera (Still in the camera function)
<perspectiveCamera ref={ref} {...props} position-y={y.to((y) => (y / 500) * 25)} />
and assign the animation a
return <a.perspectiveCamera ref={ref} {...props} position-y={y.to((y) => (y / 500) * 25)} />
And voilá, scroll activated.