Wawa Sensei logo


Starter pack

In HTML the page scroll is handled by the browser based on the content of the page. In Three.js and React Three Fiber, the Canvas is most of the time fixed taking the entire screen.

Which means that by default the scroll of the page has no effect on the 3D scene.

To remedy this, we need to listen to the scroll event and update our 3D scene accordingly.

That's exactly what ScrollControls from Drei perfectly does.


<ScrollControls/> create a HTML scroll container in front of the canvas. Its size is based on the pages prop.

One page equals the height of the screen (100vh).

Let's wrap our 3D scene in the <Canvas/> with <ScrollControls/>:

import { ScrollControls } from "@react-three/drei";

// ...

function App() {
  return (
      <Canvas camera={{ position: [0, 4, 12], fov: 30 }}>
        <ScrollControls pages={5}>
          <Experience />

export default App;

We now have a scrollable container in front of our 3D scene, nothing happens when we scroll yet.

Let's discover two ways to update the scene based on the scroll position.

Scroll component

The first way to have elements following the scroll is to use the <Scroll/> component.

It's a wrapper component that will update the position of its children based on the scroll position.

Let's add it to wrap our foodItems map in Experience.jsx:

import { Scroll } from "@react-three/drei";
// ...

export const Experience = () => {
  return (
      {/* ... */}
        {foodItems.map((foodItem, idx) => (
          <FoodItem key={idx} {...foodItem} />

// ...

Now the position of the food items is updated based on the scroll position, but we want one item per page. (Starting from the second one as the first will be an introduction)

End of lesson preview

To get access to the entire lesson, you need to purchase the course.