Next level on the web for beginners.
Table of Contents
-
What You Need to Know
Why Use a Canvas for 3D?
-
What Is an HTML Canvas?
How 3D Rendering Works on the Web
Introducing Three.js and React Three Fiber
Three.js Overview
What is React Three Fiber (R3F)?
Setting Up Your First 3D Scene
Creating a React Project
Installing Dependencies
Building a Simple Scene with a Cube
-
Loading Models with Drei
Common Pitfalls and How to Avoid Them
-
Lazy Loading & Suspense
Using Instanced Meshes and Level of Detail (LOD)
Minimizing Re-Renders
-
Disposing of Three.js Objects
Cleaning Up Event Listeners and Animations
Introduction
3D is a fascinating area in technology right now, with increasing interactivity on the web. As VR and AR spaces continue to evolve, the use of 3D objects will only grow. Even for regular web pages—such as fashion web apps, real estate sites, and educational platforms—there are significant benefits and conversions associated with the visual appeal of interactivity, which helps users feel more connected to the product. In this article, I’ll introduce you to building with 3D on the web and guide you in loading and visualizing your first 3D model on your webpage.
What You Need to Know
Before diving in, make sure you’re comfortable with these basics:
React: Familiarity with writing React components, hooks, and JSX.
JavaScript (ES6): Concepts like arrow functions, promises, and modules.
HTML & CSS: Basic knowledge for structuring and styling your pages.
If these topics sound familiar, you’re ready to explore 3D on the web!
Why Use a Canvas for 3D?
The HTML5 <canvas>
element is a powerful tool for drawing graphics using JavaScript. It’s especially useful for complex and dynamic graphics like animations and interactive 3D scenes. With a canvas, you work directly with pixels and rendering contexts, which is why libraries like Three.js were created—to simplify the process of drawing 3D graphics in the browser.
Understanding the Canvas
What Is an HTML Canvas?
An HTML canvas is an element (<canvas>
) that provides a drawable region in your web page. You can use JavaScript to draw shapes, images, or even 3D graphics on it. Think of it as a blank slate where you can paint with code.
How 3D Rendering Works on the Web
3D rendering is simply the process of drawing objects so they appear to have depth—like the things you see in video games or movies. It simulates how objects look from different angles, how light falls on them, and how textures (like wood or metal) appear. WebGL is the tool that makes these graphics run fast by using your computer's graphics card. Three.js builds on WebGL and makes it much easier for you to create detailed 3D scenes with a lot less code by abstracting lots of complexities.
Introducing Three.js and React Three Fiber
Three.js Overview
Three.js is a lightweight JavaScript library that simplifies working with WebGL. It provides:
A scene graph for organising objects.
Built-in geometries (e.g., cubes, spheres).
Lighting, cameras, and materials.
Support for animations, textures, and more.
What is React Three Fiber (R3F)?
React Three Fiber (R3F) is a tool that connects React with Three.js. It lets you create and control 3D scenes using the same simple, component-based approach you use in React. Instead of manually updating every part of your 3D scene, you simply build it using React components, which makes your code cleaner and easier to understand.
Setting Up Your First 3D Scene
Let's create a simple 3D scene using Vite, React, and React Three Fiber. This section will guide you through setting up your project and displaying a basic 3D cube.
Creating a New Vite Project
First, create a new React project with Vite by running the following commands individually in your terminal:
npm create vite@latest my-threejs-app -- --template react
cd my-threejs-app
npm install
Installing Dependencies
Next, install React Three Fiber, Drei (a set of helpful utilities for React Three Fiber), and Three.js:
npm install three @react-three/fiber @react-three/drei
Building a Simple Scene with a Cube
Now, open your project in your favourite code editor and modify the App.jsx
file to set up a basic 3D scene. Replace its contents with the following code:
// App.jsx
import React from 'react';
import { Canvas } from '@react-three/fiber';
import { OrbitControls } from '@react-three/drei';
function Box() {
return (
<mesh scale={1}>
<boxGeometry args={[1, 1, 1]} />
<meshStandardMaterial color="orange" emissive="orange" />
</mesh>
);
}
function App() {
return (
// The Canvas is like a special drawing board for 3D graphics.
<Canvas camera={{ position: [2, 1, 1] }} style={{width: '100vw', height: '100vh'}}>
{/* Ambient light lights up everything evenly */}
<ambientLight intensity={0.5} position={[1, 1, 1]} />
{/* A point light acts like a light bulb at a specific location */}
<pointLight position={[10, 10, 10]} />
{/* Our simple 3D box */}
<Box />
{/* OrbitControls let you click and drag to rotate the scene */}
<OrbitControls />
</Canvas>
);
}
export default App;
How It Works
Canvas:
This is your 3D scene container. Think of it as a special canvas where all your 3D objects are drawn.Box Component:
TheBox
component defines a simple cube using a geometry (the shape) and a material (the way it appears and its texture). The cube is coloured orange.Lights:
We add an ambient light to gently illuminate all objects and a point light to create highlights and shadows.OrbitControls:
These controls allow you to click and drag with your mouse to orbit or turn around the scene so you can view the cube from different angles.
Running Your Project
To view your first 3D scene in action, start the development server in your terminal:
npm run dev
Then, open the URL (usually http://localhost:5173
) in your browser. You should see an orange cube that you can rotate using your mouse.
Here’s how the result of what we have so far should look like:
With your mouse, you should be able to rotate the box in any direction you want and see what it looks like.
Working with 3D Models
While a simple cube is great for practice, real projects often require detailed 3D models. React Three Fiber makes it easy to load models using Drei’s hooks.
Loading Models with Drei
For example, you can load a GLTF model using the useGLTF
hook
Understanding glTF Models
A glTF (GL Transmission Format) model is a popular, open-standard file format for 3D scenes and models. It is designed for efficient transmission and loading in web applications. glTF files can include not only the 3D geometry (the shapes and vertices) but also materials, textures, animations, and lighting information. This makes glTF a great choice for complex 3D content on the web.
Why glTF?
Efficient Loading: glTF is optimized for fast loading and small file sizes.
Rich Content: It supports materials, textures, animations, and more, allowing for highly detailed scenes.
Wide Adoption: glTF is widely supported by many 3D tools and engines, making it a go-to format for 3D assets.
A Working Example
Instead of using a dummy path, let’s use a sample glTF model that you can actually run and see the result on your own browser. For example, let’s use this model I found online. You can download it by just pasting the model link in your browser, then serving it in your public folder, or use just use the direct link in your project.
Below is an example of how to load a glTF model using the useGLTF
hook from @react-three/drei
:
import React, { Suspense } from 'react';
import { Canvas } from '@react-three/fiber';
import { OrbitControls, useGLTF } from '@react-three/drei';
function Model() {
// Replace the path below with the actual path to your downloaded glTF model.
const { scene } = useGLTF('https://vazxmixjsiawhamofees.supabase.co/storage/v1/object/public/models/target-stand/model.gltf');
return <primitive object={scene} />;
}
function App() {
return (
<Canvas camera={{ position: [0, 0, 5] }} style={{width: '100vw', height: '100vh'}}>
<ambientLight intensity={1} />
<Suspense fallback={null}>
<Model />
</Suspense>
<OrbitControls />
</Canvas>
);
}
export default App;
Our gltf model has been loaded and added to our canvas. Here’s the result you should have in your browser:
Common Pitfalls and How to Avoid Them
Scaling Issues
Sometimes a 3D model might appear too big or too small when it loads. To fix this, you can adjust its size using the
scale
property. For example:<Model scale={[0.5, 0.5, 0.5]} />
In this example, the three numbers in the array represent the scaling factor for the X, Y, and Z axes respectively:
X-axis (width):
0.5
means the model's width is scaled to 50% of its original size.Y-axis (height):
0.5
means the model's height is scaled to 50%.Z-axis (depth):
0.5
means the model's depth is scaled to 50%.
You can change these values individually to adjust the model's size in each direction to better fit your scene.
Positioning:
Sometimes a model's pivot point (the center of rotation) isn't where you expect. If the model appears off-center, wrap it in a<group>
and adjust its position manually.Performance:
High-polygon models can slow down your scene. Consider using simpler models or employing Level of Detail (LOD) techniques, which swap in less detailed versions when the model is far from the camera.
6. Performance Tips
3D graphics can be demanding, so here are some tips to keep your application running smoothly.
Lazy Loading & Suspense
Load heavy assets asynchronously so that your scene doesn't freeze while waiting for models or textures to load. Wrap your model components in React's Suspense
:
<Suspense fallback={null}>
<Model />
</Suspense>
This means your app can display a fallback (or nothing) until the model is ready. For more information on React suspense click here
Instancing and Level of Detail (LOD)
Instancing:
If you need to render many similar objects (like trees or particles), use instanced meshes to reduce the number of draw calls. This technique reuses geometry and material data across many objects.LOD:
Use simpler versions of models when they’re far from the camera, and switch to detailed models only when necessary. This helps maintain high performance without sacrificing visual quality.
Minimizing Re-Renders
Memoization:
Use React'smemo
oruseMemo
to prevent unnecessary re-renders of your 3D objects.Efficient useFrame Updates:
In youruseFrame
hook (which runs every frame), only update the values that need to change. Avoid doing heavy computations insideuseFrame
to keep your frame rate smooth.
7. Cleanup Best Practices
Ensuring your application cleans up properly is key to maintaining performance and preventing memory leaks.
Disposing of Three.js Objects
When a component unmounts, Three.js objects like geometries, materials, and textures should be disposed of properly. Even though React Three Fiber does a lot for you, sometimes you need to handle this manually:
useEffect(() => {
return () => {
if (mesh) {
mesh.geometry.dispose();
mesh.material.dispose();
}
};
}, []);
Cleaning Up Event Listeners and Animations
If you add custom event listeners (for example, for mouse movements) or use GSAP animations, ensure you remove those listeners and kill animations when the component unmounts:
For Event Listeners:
useEffect(() => {
const handleMouseMove = (e) => { /* your code */ };
window.addEventListener('mousemove', handleMouseMove);
return () => window.removeEventListener('mousemove', handleMouseMove);
}, []);
Cleaning Up GSAP Animations with useGSAP
While GSAP is great for animations, it's important to clean them up to avoid memory leaks. This article isn’t focused on using GSAP, but it is great to mention as part of this section because a lot of persons would go ahead to use 3d models with some animation library and GSAP is the most popular. The useGSAP
hook from @gsap/react
makes this easy by integrating with React's lifecycle. Just return a cleanup function (like tl.kill()
) to stop the animations when your component unmounts or updates.
For example:
useGSAP(() => {
const tl = gsap.timeline();
tl.to(elementRef.current, { opacity: 1, duration: 1 });
return () => tl.kill();
}, []);
Conclusion
Three.js and React Three Fiber are powerful tools that open up a world of interactive 3D experiences in the browser. Even if you're new to HTML canvas and 3D graphics, this guide shows that you can start simple—with just a basic cube—and gradually build more complex scenes.
Key Points to Remember:
Start Small: Begin with simple shapes like cubes and gradually introduce more complexity.
Plan for Performance: Use lazy loading, instancing, and memoization to ensure your 3D scene runs smoothly.
Clean Up Properly: Dispose of objects, remove event listeners, and kill animations to prevent memory leaks and maintain performance.
Experiment and Learn: 3D development is a process of trial and error. As you encounter challenges (like scaling issues or model positioning), use the tips provided to troubleshoot and improve your setup.
With these steps and best practices, you'll be well on your way to creating stunning 3D applications that are both visually impressive and highly efficient. Happy coding, and enjoy your journey into the exciting world of 3D web development!