Three.js React Three Fiber Bento

January 31, 2024

Using React Three Fiber in a beginner task

In this task, we create a simple tutorial that shows how to start a basic project using React Three Fiber and Vite with TypeScript. The goal of the project is to create a simple "bento" box, one part of which we can move interactively. Finished site here

Installing necessary packages

POWERSHELL
npm create vite@latest

Choose the react + typescript + SWC

POWERSHELL
npm install three @types/three @react-three/fiber

Due to the project, the following installations are still necessary:

POWERSHELL
@react-three/drei @react-three/csg

App.tsx

Imports

  • Canvas: contains the 3D elements
  • Canvas Components:

  • gl: includes the WebGL renderer settings, such as 'antialias' edge smoothing
  • camera: the camera properties, such as field of view and position
  • shadow: enables shadows.
  • TYPESCRIPT
    //App.tsx
    import { Canvas } from "@react-three/fiber";
    import { Scene } from "./Scene";
    import { ACESFilmicToneMapping, sRGBEncoding } from "three";
    function App() {
    return (
    <Canvas
    dpr={[1, 2]}
    gl={{
    antialias: true,
    toneMapping: ACESFilmicToneMapping,
    outputEncoding: sRGBEncoding,
    }}
    camera={{
    fov: 10,
    near: 0.1,
    far: 200,
    position: [0, 9, 9],
    }}
    shadows
    >
    <Scene />
    </Canvas>
    );
    }
    export default App;

    Scene.tsx

    We now add the 3D elements to the previously created canvas. First, we create a simple cube using new Three.BoxGeometry to test the environment.

  • The OrbitControls setting up a component that handles user interactions.
  • The directionalLight and the ambientLight adding elements that provide the scene's lighting.
  • TYPESCRIPT
    //Scene.tsx
    import { OrbitControls, PivotControls } from "@react-three/drei";
    import { Base, CSGGeometryRef, Geometry } from "@react-three/csg";
    import * as THREE from "three";
    import { useRef } from "react";
    const box = new THREE.BoxGeometry();
    function Scene() {
    const csg = useRef<CSGGeometryRef>(null);
    return (
    <>
    <OrbitControls makeDefault />
    <directionalLight
    position={[-2, 2, 3]}
    intensity={0.8}
    castShadow
    shadow-mapSize={[1024 * 2, 1024 * 2]}
    />
    <ambientLight intensity={0.2} />
    <mesh receiveShadow castShadow>
    <Geometry ref={csg}>
    <Base name="base" geometry={box} scale={[1.4, 0.2, 2]}></Base>
    </Geometry>
    <meshStandardMaterial color="#A1662F" envMapIntensity={0.05} />
    </mesh>
    </>
    );
    }
    export { Scene };

    If the environment is functioning properly, we will create our simple bento storage box.

    Here, we first add a flat plane on which the shadows will appear.

    TYPESCRIPT
    //Plane.tsx
    function Plane() {
    return (
    <mesh
    rotation-x={-Math.PI / 2}
    position={[0, -0.1, 0]}
    scale={[10, 10, 10]}
    receiveShadow
    >
    <planeGeometry />
    <shadowMaterial transparent opacity={0.4} />
    </mesh>
    );
    }
    export { Plane };

    Add the plane to Scene.tsx

    TYPESCRIPT
    //Scene.tsx
    import { Plane } from "./components/Plane";
    ...
    <ambientLight intensity={0.2} />
    <Plane />
    ...

    We create the base for the cutouts, whose position and size we can modify with each call.

    TYPESCRIPT
    //SubtractBox.tsx
    import { Geometry, Subtraction } from "@react-three/csg";
    import * as THREE from "three";
    const box = new THREE.BoxGeometry();
    type SubtractBoxProps = {
    position?: [number, number, number];
    scale?: [number, number, number];
    };
    const SubtractBox: React.FC<SubtractBoxProps> = (props) => (
    <Subtraction {...props}>
    <Geometry>
    <Subtraction geometry={box} />
    </Geometry>
    </Subtraction>
    );
    export { SubtractBox };

    We add our created cutout to Scene.tsx. To our cutout, we also add a controller that allows us to move it.

    TYPESCRIPT
    //Scene.tsx
    import { SubtractBox } from "./components/SubtractBox";
    ...
    <mesh receiveShadow castShadow>
    <Geometry ref={csg}>
    <Base name="base" geometry={box} scale={[1.4, 0.2, 2]}></Base>
    <PivotControls
    activeAxes={[true, true, true]}
    scale={0.2}
    anchor={[0, 0, 0]}
    onDrag={() => {
    if (csg.current) {
    csg.current.update();
    }
    }}
    >
    <SubtractBox position={[0, 0.2, 0]} scale={[1.2, 0.4, 1]} />
    </PivotControls>
    </Geometry>
    <meshStandardMaterial color="#A1662F" envMapIntensity={0.05} />
    </mesh>
    ...

    We can add multiple cutouts to the base object to create our bento box.

    Where we can go from here

    This is a fairly basic program, but a good starting point for React Three Fiber and understanding the 3D environment in Node.js.

    Code

    The complete code can be found: https://github.com/balazsfaragodev/r3f-vite-ts-bento

    Share this article

    The Newsletter for Next-Level Tech Learning

    Start your day right with the daily newsletter that entertains and informs. Subscribe now for free!

    Related Articles