Phone: +43 699 182 230 65
Email: thomas@schorn.io
Mühlkreisbahnstraße 7
4040 Linz
AUSTRIA

Open in Google Maps
Open in OpenStreetMap

  • Home
  • Web Development
  • Blog
  • Showcases
  • About us
  • Contact
  • Data Protection
  • Imprint

Build Interactive 3D Icons with React Three Fiber

Mateus Fontoura

Mateus Fontoura

•

11 April 2024

•

6 min read

One interesting way to stand out and attract your user’s attention is to use 3D elements in your web experiences. In this post, we’re going to see how we can create interactive 3D icons using React and React Three Fiber (R3F) with TypeScript. If you don’t want to use TS that’s alright, just remove the types whenever needed.

At the end of this post, you can find the link for the complete code.

Dependencies

To get started, install the following dependencies in your React app: three: The core Three.js library, which allows us to work with 3D objects in the browser. react-three/fiber: A React renderer for Three.js. @react-three/drei: A helpful toolkit for react-three/fiber.

To install them, type in your terminal

npm install three @react-three/fiber @react-three/drei 

Creating the 3D Icons

Setting up the Canvas and Lighting

Next, we need to wrap our 3D elements in the Canvas component from @react-three/fiber:

import { Canvas } from "@react-three/fiber";

function App() {
  return (
    <div className="App">
      <Canvas
        style={{ width: "100vw", height: "90vh" }} //to make our canvas take almost the whole screen
        camera={{ position: [0, 0, 15] }} //’zoom out’ of 15 meters
      >
        <directionalLight position={[0, 1, 2]} intensity={5} color="white" />
        <ambientLight intensity={0.6} />
        {icons.map((icon, index) => {
        const gap = 5;
        // prettier-ignore
        const horizontalPosition = gap - (index * gap);

        return (
          <Icon3D
            imagePath={icon}
            position={[horizontalPosition, 1, 0]}
            shape={shape}
          />
        );
      })}

      </Canvas>
}
  • directionalLight: enhances the shading and lighting, providing depth. We can play around with the ‘position’ and ‘intensity’ to our taste.

  • ambientLight: provides a uniform light to the scene.

  • icons.map: in this code, we’re mapping through an array of icons, but if you prefer, you can add just one ‘Icon3D’ passing as the imagePath you desired icon.

Defining the Icon3D Component

This is where we’re going to put the icons and generate the shapes. Let’s see the complete code, then we visit step by step what’s happening:

import { Decal, Float, useTexture } from "@react-three/drei";
import { useFrame } from "@react-three/fiber";
import { useRef, useState } from "react";
import { Mesh } from "three";
import { white, blue } from "../../App";

const RADIUS = 2;

export function Icon3D({ imagePath, position, shape }: Icon3DProps) {
  const texture = useTexture(imagePath);

  return (
        <mesh>
 	<dodecahedronGeometry args={[RADIUS, 0]} />
            <meshStandardMaterial
           	 	metalness={0.6} //to add a more ‘real’ metallic feeling to the icon
           		roughness={0.5}
                />
          <Decal
            position={[0, 0, 2]}
            rotation={[2 * Math.PI, 0, 6.25]}
            scale={1}
            map={texture}
          />
        </mesh>
  );
}
  • useTexture loads textures for our icons.

  • 'mesh': in R3F, our 3D elements are wrapped in a mesh. The mesh needs geometry and material. Think of the mesh as the complete body, the geometry as the bones, and the material as the skin.

  • 'dodecahedronGeometry': The specific shape of this mesh, but there are other possibilities. All geometries available in Three.js can be used in R3F. For more information, check Three.js documentation or R3F docs.

  • 'meshStandardMaterial': The skin of our mesh, influences how the shades and lights interact with the mesh. For more information, search the documentation.

  • 'Decal': This is a component that comes from '@react-three/drei', and allows us to add an image on a surface. We can play with the position, rotation, and scale to make it fit correctly. Then, we pass our texture to its map props.

Adding Interactivity to 3D elements

Now that we have the barebones of our 3D Icon, we can start adding extra functionality, such as user interaction.

One of the coolest things about R3F is the possibility of interacting with 3D elements as React components, so we can use React’s event-handling patterns. For instance, in case we want to add hover and click events, it’s pretty practical:

const mesh = useRef<Mesh | null>(null); //we initialize the reference to the mesh, so we can interact with it 
const [hovered, setHovered] = useState(false);
const [clicked, setClicked] = useState(false);

// Inside the component's return statement
<mesh
  ref={mesh} // we pass the ref to the mesh
  onPointerEnter={() => setHovered(true)} // mesh recognizes other events too
  onPointerLeave={() => setHovered(false)}   
  onClick={() => setClicked(!clicked)}
>
  {/* ... */} // we can then personalize what the interactions do to the mesh
</mesh>
  • The meshes recognize several different events. To see all of them, check out the R3F docs on events.

Conclusion

By leveraging React and R3F, we open up a new world of possibilities for web experience. We can use the familiar characteristics of React with the power of Three.js through R3F in an intuitive way.

Hopefully, this post provided you with the foundational knowledge to get started with this powerful combination.

To explore more, you can access the complete code here.

See you next time!

Front end

Written by

Mateus Fontoura

Mateus Fontoura

Full-Stack Web Developer at Schorn.io.

Read next

  • AI in a box!
  • “Wow” 🤩, “boah” 😲 and “crazy” 🤪
  • AI chatbot - why? Current use cases
  • 'Space Traveler': A Glimpse into the Future of Web Technologies
  • Take advantage of current grants
  • How to Optimize GLB Files for Web Projects
All articles