Edupala

Comprehensive Full Stack Development Tutorial: Learn Ionic, Angular, React, React Native, and Node.js with JavaScript

Comprehensive Guide to Integrating Threejs in Nextjs

Threejs in Nextjs with example

Integrating Three.js with Reactjs or Next.js can be a powerful way to create dynamic 3D web applications. We will learn what are basic concept that need to grasp before integrating it with any frontend framwork of your choice. This is part one of our threejs on Nextjs.

1. Core Components of Three.js

Here are most basic concept that are need for all the Three.js project requires at least the following components:

  • Scene: The scene is the container that holds all objects, lights, and cameras. It’s like the canvas for your 3D content.
  • Camera: Defines the viewpoint from which the scene is observed or rendered. Three.js provides several camera types, including PerspectiveCamera and OrthographicCamera.
  • Renderer: The renderer is responsible for drawing the scene and objects onto the canvas. You typically use WebGLRenderer. The renderer brings everything together into the final product that we see on the screen. The renderer takes a 3D scene, environment, objects, lighting, and other elements that are integrated into the scene and, based on the camera perspective, calculates how everything should look on your 2D screen. It processes every pixel, determining the colors, textures, lighting, shadows, and more to produce that final image.
  • Objects and Meshes: The 3D objects that populate the scene, often created using geometry and material. The object can be simple shape like a cube or sphere, or a more complex object created from multiple meshes.
  • Meshes: This is a combination of geometry and material. The geometry defines the shape of the object, while the material defines its appearance.
  • Geometry: This defines the shape of an object. Three.js provides many built-in geometries, such as BoxGeometry, SphereGeometry, and PlaneGeometry.
  • Material: This defines the appearance of an object. Three.js provides various material types, including BasicMaterial, LambertMaterial, and PhongMaterial.
  • Light: This provides illumination for the scene. Three.js offers different light types, such as AmbientLight, PointLight, and DirectionalLight.

2. Install and Configure Threejs in Nextjs

First, let’s create the Next.js or React.js project. Once we have the project, let’s install Three.js plus TypeScript dependencies for Three.js in our Three.js React project.

npm i three
npm i --save-dev @types/three

3. Abstract step for implementing Threejs in Nextjs

To get started with Three.js, you need to install the library and set up a basic scene, camera, and renderer. This can be done using the following steps:

  1. Install Three.jsnpm install three with typescript dependency
  2. Create a Scene: We start with scene, Initialize a new scene object.
  3. Add a Camera: Set up a camera to view the scene to determine the view point and perspective of the scene
  4. Object to populate the scene with shape, model and other 3D model.
  5. Add lightning illumate the scene, so object can be seen and appears as real.
  6. We update object overtime for animation
  7. Renderer: Create a renderer to display the scene at the end.

Here are the general list that provides a high-level overview of the steps needed to implement Three.js in a Next.js project. Each step can be expanded into more detailed instructions as needed for your specific project requirements.

  1. Set up a new Next.js project with TypeScript support Install Three.js as a dependency Create a new component for the Three.js scene Set up the basic Three.js elements: Scene, Camera (PerspectiveCamera) example, Renderer (WebGLRenderer)
  2. Create a container for the Three.js canvas Initialize the scene, camera, and renderer in a useEffect hook
  3. Add basic 3D objects to the scene (e.g., a cube)
  4. Set up lighting in the scene
  5. Implement the animation loop
  6. Handle component unmounting and cleanup
  7. Make the scene responsive to window resizing
  8. Implement loading of external 3D models or textures (if required)
  9. Integrate the Three.js component into your Next.js pages
  10. Handle server-side rendering considerations

Here are the abstract steps we need to implement to integrate threejs in nextjs project.

  • Initial setup and define scene, camera, renderer STEP1: Add the scene in the project
  • Step 2: Camera setup, we will use PerspectiveCamera(fov, aspect, near, far) among different camera.
  • The renderer is responsible for drawing the scene to the screen.

4. Details of threejs component in details

1. Camera :

Check more on threejs camera with realworld example. Mastering Threejs Camera: Types, Controls, and Real-World Examples

2. Object:

The threej object is anything that you seen or interact in 3 D spaces and their are many different types of 3D object and each had its own purpose.

3. Mesh

Messh is most common object in 3D js and its made of two main part and it is the combination of a geometry and a material, representing a 3D object in the scene. Example cube is made by combining box Geometry and material.

const cube = new THREE.Mesh(geometry, material);
scene.add(cube);

3. Points

Points is another object in Three.js, it is specifically designed for rendering particles or vertices and stars, rather than full 3D shapes like meshes. But most common object is mesh.

4. Lines

line is also an object, and it’s represented by the class Line. It is often used to draw connections between points, create shapes, grids, or wireframes.

5. Group

Group is also an object, and it’s like a container (similar to a div in HTML) that can hold multiple objects. The Group class allows you to organize multiple objects together, so you can manipulate or transform them as a single unit.

6. Renderer

The renderer is responsible for drawing the scene to the screen. The renderer is responsible for drawing the scene and objects onto the canvas. You typically use WebGLRenderer.

const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

Mesh in 3Djs in Details

In Three.js, a mesh is a combination of a geometry (shape) and a material (appearance), which together define a 3D object that can be rendered in the scene.

1. Geometry

In Three.js, geometry is what gives 3D objects their shape. Geometries define the shape of 3D objects. It’s like the skeleton of any 3D model you see on screen. Let’s break it down into three simple parts:

1.1. Vertices: The Corner Points

  • Vertices are just points in 3D space.
  • They’re like the corners of a shape.
  • Each vertex has an x, y, and z coordinate to show where it is.
  • For example, a cube has 8 vertices (one at each corner).
const vertex = new THREE.Vector3(1, 1, 1);  // x=1, y=1, z=1

creates a new instance of a Vector3 object in Three.js, which represents a point in 3D space. The parameters (1, 1, 1) specify the coordinates of the point, where x = 1, y = 1, and z = 1. This means the vertex is located at the position (1, 1, 1) in the 3D coordinate system.

1.2 Edges: The Connecting Lines

Edges are straight lines that connect two vertices. They outline the shape of your object. In a cube, there are 12 edges (think of the lines you’d draw to make a cube).

// Create a cube geometry
const geometry = new THREE.BoxGeometry(1, 1, 1);

// Create edges geometry
const edgesGeometry = new THREE.EdgesGeometry(geometry);
  • THREE.BoxGeometry is a class in Three.js used to create a cube or box shape.
  • The parameters (1, 1, 1) specify the width, height, and depth of the box, respectively.
  • This creates a cube with each side measuring 1 unit in the 3D coordinate system.

1.3. Faces: The Flat Surfaces

  • Faces are flat surfaces that fill the space between edges.
  • They make up the visible surface of your 3D object.
  • Faces are usually triangles in Three.js (even for a square face, it’s made of two triangles).
  • A cube has 6 faces (each side is a face).

Putting It All Together: A Simple Cube:

Here’s how you might create a simple cube in Three.js:

const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
const cube = new THREE.Mesh(geometry, material);

In this example:

  • BoxGeometry automatically creates all the vertices, edges, and faces for a cube.
  • The cube has 8 vertices, 12 edges, and 6 faces.
  • We don’t have to define these manually – Three.js does it for us!

Remember:

  • Vertices are the corner points.
  • Edges are the lines connecting vertices.
  • Faces are the flat surfaces that make up the visible part of the shape.

Example of Geometry in 3Djs

const geometry = new THREE.BoxGeometry(1, 1, 1);

#Cylinder
const cylinderGeometry = new THREE.CylinderGeometry(1, 1, 2, 32);
#Cone
const coneGeometry = new THREE.ConeGeometry(1, 2, 32);

const coneGeometry = new THREE.ConeGeometry(1, 2, 32);

#Knot
const torusKnotGeometry = new THREE.TorusKnotGeometry(1, 0.4, 100, 16);

#dodecahedron
const dodecahedronGeometry = new THREE.DodecahedronGeometry(1);

Creating custom Geometry

We can create custom Geometry by define object vertices, edges and faces directly in the code, we can define whatever we can and create a new shape.

const shape = new THREE.Shape();
shape.moveTo(0, 0);
shape.lineTo(0, 1);
shape.lineTo(1, 1);
shape.lineTo(1, 0);
shape.lineTo(0, 0);

const extrudeSettings = {
  steps: 2,
  depth: 1,
  bevelEnabled: true,
  bevelThickness: 0.2,
  bevelSize: 0.1,
  bevelSegments: 1
};

const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);

Remember, after creating any of these geometries, you’ll need to pair them with a material and create a mesh to add them to your scene:

const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);

2. Materials in Three.js: Giving Life to 3D Objects

Second part of the mesh is Material determines the surface of the geometry looks. In Three.js, materials determine how the surface of a 3D object looks. They’re like the skin or paint on top of the geometry. Materials define several key aspects of an object’s appearance:

  1. Color: The basic color of the object.
  2. Texture: Images or patterns applied to the surface.
  3. Transparency: How see-through the object is.
  4. Shininess: How glossy or matte the surface appears.
  5. Light Interaction: How the object responds to lights in the scene.

Basic Types of Materials

Three.js offers several types of materials. Here are some common ones:

  1. MeshBasicMaterial: A simple material that isn’t affected by lights and its only applys flat color to an object but its doesn`t interact with the light.
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
  1. MeshStandardMaterial: A physically based material that looks more realistic. It offer color, roughness and metalness controls.
const material = new THREE.MeshStandardMaterial({ 
  color: 0x00ff00,
  roughness: 0.5,
  metalness: 0.5
});
  1. MeshPhongMaterial: Good for shiny surfaces.
const material = new THREE.MeshPhongMaterial({ 
  color: 0x00ff00,
  shininess: 100
});

Key Properties of Materials

  • color: Sets the color of the material.
  • map: Applies a texture to the material.
  • transparent and opacity: Control transparency.
  • wireframe: Shows only the edges of the geometry.

Example: Applying a Material

Here’s how you might apply a material to a cube:

// Create a geometry
const geometry = new THREE.BoxGeometry(1, 1, 1);

// Create a material
const material = new THREE.MeshStandardMaterial({
color: 0x00ff00,
roughness: 0.5,
metalness: 0.1
});

// Create a mesh by combining geometry and material
const cube = new THREE.Mesh(geometry, material);

In this example, we’ve created a green cube with a slightly rough, metallic surface.

Remember, materials work hand-in-hand with lighting in your scene. The type of material you choose and how you configure it will determine how your object looks under different lighting conditions. There are so many other material offers by 3djs.

6.Lights

Lights illuminate the objects in your scene. Common types include:

  1. DirectionalLight: Parallel light rays, like sunlight
  2. AmbientLight: Illuminates all objects equally
  3. PointLight: Emits light from a single point in all directions
const ambientLight = new THREE.AmbientLight(0x404040);
scene.add(ambientLight);

const pointLight = new THREE.PointLight(0xffffff, 1, 100);
pointLight.position.set(10, 10, 10);
scene.add(pointLight);

5. Animation

The animation loop continuously renders the scene, allowing for movement and interactivity.

function animate() {
  requestAnimationFrame(animate);
  cube.rotation.x += 0.01;
  cube.rotation.y += 0.01;
  renderer.render(scene, camera);
}
animate();
Threejs in nextjs

We have two example one sphere and cube, this is screenshot, in actual this object have animation. Here are code of both threejs examples.

#Example Sphere
"use client";

import React, { useRef, useEffect } from "react";
import * as THREE from "three";

const Sphere = () => {
  const canvasRef = useRef<HTMLCanvasElement>(null);

  useEffect(() => {
    if (!canvasRef.current) return;

    const canvas = canvasRef.current;

  // Get the parent element for the canvas 
    const parentElement = canvas.parentElement;
    if (!parentElement) return;

    // Set up the scene, camera, and renderer
    const scene = new THREE.Scene();
    const camera = new THREE.PerspectiveCamera(
      75,
      parentElement.clientWidth / parentElement.clientHeight,
      0.1,
      1000
    );
    camera.position.z = 5;

    const renderer = new THREE.WebGLRenderer({
      canvas: canvas,
      antialias: true,
    });
    renderer.setSize(parentElement.clientWidth, parentElement.clientHeight);
    renderer.setPixelRatio(window.devicePixelRatio);

    // Create a sphere geometry and material
    const geometry = new THREE.SphereGeometry(1, 32, 32);
    const material = new THREE.MeshPhongMaterial({ color: 0xff7300 });

    // Create a sphere mesh and add it to the scene
    const sphere = new THREE.Mesh(geometry, material);
    scene.add(sphere);

    // Add lighting
    const ambientLight = new THREE.AmbientLight(0x404040);
    const directionalLight = new THREE.DirectionalLight(0xffffff, 2);
    directionalLight.position.set(1, 1, 1);
    scene.add(ambientLight, directionalLight);

    // Animation loop
    const animate = () => {
      sphere.rotation.x += 0.01;
      sphere.rotation.y += 0.01;
      renderer.render(scene, camera);
      requestAnimationFrame(animate);
    };
    animate();

    // Handle container resizing
    const handleResize = () => {
      if (!parentElement) return;
      const width = parentElement.clientWidth;
      const height = parentElement.clientHeight;
      renderer.setSize(width, height);
      camera.aspect = width / height;
      camera.updateProjectionMatrix();
    };
    window.addEventListener("resize", handleResize);

    // Cleanup function
    return () => {
      window.removeEventListener("resize", handleResize);
      renderer.dispose();
      geometry.dispose();
      material.dispose();
    };
  }, []);

  return <canvas ref={canvasRef} style={{ width: "100%", height: "100%" }} />;
};

export default Sphere;

#Example Cube

"use client";

import { useEffect, useRef, useState, useCallback } from "react";
import * as THREE from "three";

const Cube = () => {
  const mountRef = useRef<HTMLDivElement>(null); 
// Reference to the container div
  const animationFrameId = useRef<number | null>(null); 
// Ref to store the animation frame ID

  // State for size management
  const [size, setSize] = useState({ width: 0, height: 0 });

  // Three.js objects stored in refs to prevent re-creation
  const sceneRef = useRef<THREE.Scene | null>(null);
  const cameraRef = useRef<THREE.PerspectiveCamera | null>(null);
  const rendererRef = useRef<THREE.WebGLRenderer | null>(null);
  const cubeRef = useRef<THREE.Mesh | null>(null);

  // Update the size of the renderer and camera
   //callback function for window resize
  const updateSize = useCallback(() => {
    if (mountRef.current && cameraRef.current && rendererRef.current) {
      const { clientWidth, clientHeight } = mountRef.current;
      setSize({ width: clientWidth, height: clientHeight });

      // Update camera aspect ratio and renderer size
      cameraRef.current.aspect = clientWidth / clientHeight;
      cameraRef.current.updateProjectionMatrix();
      rendererRef.current.setSize(clientWidth, clientHeight);
    }
  }, []);

  // Initialization of the Three.js scene, camera, renderer, and cube
  useEffect(() => {
    if (!mountRef.current) return;

    // Scene
    const scene = new THREE.Scene();
    sceneRef.current = scene;

    // Camera
    const camera = new THREE.PerspectiveCamera(
      75,
      mountRef.current.clientWidth / mountRef.current.clientHeight,
      0.1,
      1000
    );
    camera.position.z = 5;
    cameraRef.current = camera;

    // Renderer
    const renderer = new THREE.WebGLRenderer();
    renderer.setSize(
      mountRef.current.clientWidth,
      mountRef.current.clientHeight
    );
    mountRef.current.appendChild(renderer.domElement);
    rendererRef.current = renderer;

    // Cube
    const geometry = new THREE.BoxGeometry();
    const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
    const cube = new THREE.Mesh(geometry, material);
    scene.add(cube);
    cubeRef.current = cube;

    // Start the animation loop
    const animate = () => {
      if (cubeRef.current) {
        cubeRef.current.rotation.x += 0.01;
        cubeRef.current.rotation.y += 0.01;
      }

      if (rendererRef.current && sceneRef.current && cameraRef.current) {
        rendererRef.current.render(sceneRef.current, cameraRef.current);
      }

      animationFrameId.current = requestAnimationFrame(animate);
    };
    animate();

    // Update size initially
    updateSize();

    // Cleanup function
    return () => {
      if (animationFrameId.current)
        cancelAnimationFrame(animationFrameId.current);
      if (rendererRef.current) {
        rendererRef.current.dispose();
        mountRef.current?.removeChild(rendererRef.current.domElement);
      }
    };
  }, [updateSize]);

  // Handle window resizing
  useEffect(() => {
    const handleResize = () => {
      updateSize();
    };
    window.addEventListener("resize", handleResize);

    return () => {
      window.removeEventListener("resize", handleResize);
    };
  }, [updateSize]);

  return <div ref={mountRef} style={{ width: "100%", height: "100%" }} />;
};

export default Cube;
#Need to allocate space between our two example as both are different component and different scene
const Page = () => {
  return (
    <div style={{ display: "flex", width: "100vw", height: "100vh" }}>
      <div style={{ width: "50%", height: "100%" }}>
        <Sphere />
      </div>
      <div style={{ width: "50%", height: "100%" }}>
        <Cube />
      </div>
    </div>
  );
};

Textures in Three.js: Adding Detail to 3D Objects

In Three.js, textures are images applied to the surface of 3D objects to add visual details and realism. Think of textures like wrapping paper for your 3D models – they cover the geometry to make it look more interesting or lifelike.

Basic Concept

  • Textures are typically image files (JPEG, PNG, GIF, etc.)
  • They’re applied to materials, which are then applied to meshes
  • Textures can add color, patterns, or even simulate surface properties

Loading a Texture

Here’s how you might load and apply a basic texture:

const textureLoader = new THREE.TextureLoader();
const texture = textureLoader.load('path/to/your/texture.jpg');
const material = new THREE.MeshBasicMaterial({ map: texture });

Types of Textures in Three.js

  1. Color Map (Diffuse Texture)
    • The most common type
    • Defines the base color or pattern of the surfac
material.map = colorTexture;

Normal Map

  • Adds the illusion of small surface details without extra geometry
  • Makes the surface appear more detailed under lighting
material.normalMap = normalTexture;

Bump Map

  • Similar to normal maps, but simpler
  • Creates an illusion of depth on the surface
material.bumpMap = bumpTexture;

Displacement Map

  • Actually modifies the geometry to create real depth
  • More resource-intensive than bump or normal maps
material.displacementMap = displacementTexture;

Specular Map

  • Controls the shininess of different parts of the surface
  • Makes some areas more reflective than others
material.specularMap = specularTexture;

Alpha Map

  • Controls the transparency of different parts of the surface
material.alphaMap = alphaTexture;
material.transparent = true;

Remember, textures can dramatically improve the visual quality of your 3D scenes, but they also impact performance. Use them wisely to balance realism and efficiency in your Three.js projects!

Illuminating Your Scene: A Guide to Lights in Three.js

In Three.js, lights are crucial for making your 3D scenes visible and realistic. Without lights, your 3D objects would be completely dark. Let’s explore the basics of lighting in Three.js.

Why Lights Matter

  • Lights make objects visible
  • They create shadows and depth
  • Proper lighting enhances realism and mood

Types of Lights in Three.js

1. Ambient Light

Real-life example: Overcast day. On a cloudy day, light is scattered in all directions, illuminating everything evenly without harsh shadows. This is similar to how ambient light works in Three.js. Ambient light properties

  • Illuminates all objects in the scene equally
  • No specific direction, no shadows
  • Good for providing overall soft illumination
const light = new THREE.TypeOfLight(parameters);
scene.add(light);

2. Point Light

Real-life example: Light bulb. A bare light bulb in a room emits light in all directions from a single point, just like a point light in Three.js. Point light properties

  • Emits light in all directions from a single point
  • Like a lightbulb in a room
  • Can cast shadows
const pointLight = new THREE.PointLight(0xffffff, 1, 100);
pointLight.position.set(0, 10, 0);
scene.add(pointLight);

3. Directional Light

Real-life example: Sunlight. The sun, being so far away, casts light rays that are essentially parallel when they reach Earth. This is how directional light behaves in Three.js. It properties include

  • Emits light in a specific direction
  • Rays are parallel (like sunlight)
  • Good for simulating sunlight
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);
directionalLight.position.set(5, 5, 5);
scene.add(directionalLight);

Use case: Simulating sunlight or any distant, powerful light source.

4. Spot Light

Real-life example: Flashlight or stage spotlight. A flashlight or a spotlight in a theater creates a cone of light, illuminating a specific area. This is exactly what a spot light does in Three.js.

  • Emits light in a cone shape
  • Like a flashlight or spotlight
  • Can cast shadows
const spotLight = new THREE.SpotLight(0xffffff, 1);
spotLight.position.set(0, 10, 0);
spotLight.angle = Math.PI / 4;
scene.add(spotLight);

Use case: Creating focused lighting effects, like a car’s headlights or a spotlight on a stage.

5. Hemisphere Light

Real-life example: Outdoor lighting on a clear day. On a clear day, you have blue sky above and reflected light from the ground below. Hemisphere light in Three.js simulates this by fading between two colors.

  • Fades between two colors
  • Good for simulating outdoor lighting
const hemisphereLight = new THREE.HemisphereLight(0xffffbb, 0x080820, 1);
scene.add(hemisphereLight);

Use case: Creating realistic outdoor lighting in 3D environments.

Tips for Using Lights

  1. Combine Light Types: Use multiple light types for more realistic scenes.
  2. Adjust Intensity: The second parameter in most lights controls brightness.
  3. Position Matters: Experiment with light positions for different effects.
  4. Shadows: Enable shadows on lights and objects for added realism.
renderer.shadowMap.enabled = true;
directionalLight.castShadow = true;
  1. Performance: Too many lights can slow down your scene. Use them wisely!

Example: A Basic Lit Scene

Here’s a simple example combining a few light types:

const scene = new THREE.Scene();

// Ambient light for overall illumination
const ambientLight = new THREE.AmbientLight(0x404040);
scene.add(ambientLight);

// Directional light for sun-like effect
const dirLight = new THREE.DirectionalLight(0xffffff, 0.5);
dirLight.position.set(5, 5, 5);
scene.add(dirLight);

// Point light for specific highlighting
const pointLight = new THREE.PointLight(0xff0000, 1, 100);
pointLight.position.set(0, 10, 0);
scene.add(pointLight);

// Your 3D objects would go here

Remember, lighting in 3D scenes is an art. Experiment with different combinations and settings to achieve the look you want!

Combining Lights: A Living Room Scene

Let’s create a simple living room scene using multiple light types:

// Ambient light for general room illumination (like light coming through windows)
const ambientLight = new THREE.AmbientLight(0x404040, 0.5);
scene.add(ambientLight);

// Directional light to simulate sunlight coming through a window
const sunLight = new THREE.DirectionalLight(0xffffff, 0.6);
sunLight.position.set(-1, 1, 1);
scene.add(sunLight);

// Point light for a table lamp
const lampLight = new THREE.PointLight(0xff9000, 0.8, 5);
lampLight.position.set(2, 1, -1);
scene.add(lampLight);

// Spot light for a reading light
const readingLight = new THREE.SpotLight(0xffffff, 0.8);
readingLight.position.set(-2, 2, -1);
readingLight.angle = Math.PI / 6;
scene.add(readingLight);

In this scene:

  • Ambient light simulates the overall room lighting.
  • Directional light acts as sunlight streaming through a window.
  • A point light represents a warm-colored table lamp.
  • A spot light serves as a focused reading light.

By combining these lights, we create a rich, realistic lighting environment similar to what you might find in an actual living room.

Best Practices of using Threejs in Nextjs

Performance optimization:

  • Use efficient geometries and limit the number of objects in your scene.
  • Implement level-of-detail (LOD) techniques for complex scenes.
  • Use object pooling for frequently created/destroyed objects.

Responsive design:

  • Handle window resizing to maintain proper aspect ratio and fill the viewport.
  • Consider using THREE.OrthographicCamera for consistent sizing across devices.

Asset management:

  • Use a loader manager to handle multiple asset loads efficiently.
  • Implement progress indicators for large asset loads.

Code organization:

  • Separate Three.js logic into reusable classes or hooks.
  • Use a state management solution (e.g., React context or Redux) for complex applications.

Testing:

  • Implement unit tests for your Three.js logic.
  • Use snapshot testing for visual regression testing.

Accessibility:

  • Provide alternative text descriptions for 3D content.
  • Implement keyboard controls where appropriate.

React Three Fiber Solar System Example

We have cover most of the basic concept that are essential to used threejs in Nextjs or reactjs. First create reactproject where you need to install following packages.

npm i three
npm i @react-three/drei
npm i @react-three/drei

React Three Fiber that demonstrates different concepts. Let’s create a simple solar system with orbiting planets.

This example demonstrates several React Three Fiber concepts:

  1. Utilizing Drei components (OrbitControls and Stars)
  2. Creating and positioning 3D objects
  3. Using basic and standard materials
  4. Implementing custom components (Planet and Sun)
  5. Using useFrame for animations
  6. Adding lighting (point light and ambient light)

This example creates a simple solar system scene with a sun and three orbiting planets. Here’s a breakdown of the code:

  1. We import necessary dependencies from React, React Three Fiber, and Drei.
  2. We define a Planet component that takes properties for position, size, color, orbit radius, and orbit speed. It uses useFrame to update its position, creating an orbital motion.
  3. We create a Sun component that serves as the center of our solar system. It emits light using a pointLight.
  4. In the main App component, we set up the Canvas with a black background and add some ambient light for general illumination.
  5. We use the Stars component from Drei to create a starry background.
  6. We add the Sun and three Planet components with different properties to create our solar system.
  7. OrbitControls is added to allow user interaction with the scene.
#Sun component 
import React from "react";

const Sun = () => {
  return (
    <mesh>
      {/* eslint-disable-next-line react/no-unknown-property */}
      <sphereGeometry args={[2.5, 32, 32]} />
      <meshBasicMaterial color="#FDB813" />
      {/* eslint-disable-next-line react/no-unknown-property */}
      <pointLight color="#FDB813" intensity={1.5} distance={50} />
    </mesh>
  );
};

export default Sun;
#Planet component 
import React, { useRef } from "react";
import { useFrame } from "@react-three/fiber";
import { Vector3 } from "three";
import * as THREE from "three";

interface PlanetProps {
  position: [number, number, number];
  size: number;
  color: string;
  orbitRadius: number;
  orbitSpeed: number;
}

const Planet: React.FC<PlanetProps> = ({
  position,
  size,
  color,
  orbitRadius,
  orbitSpeed,
}) => {
  const ref = useRef<THREE.Mesh>(null);

  useFrame(({ clock }) => {
    if (ref.current) {
      const t = clock.getElapsedTime() * orbitSpeed;
      ref.current.position.x = Math.cos(t) * orbitRadius;
      ref.current.position.z = Math.sin(t) * orbitRadius;
    }
  });

  return (
    <mesh ref={ref} position={new Vector3(...position)}>
      <sphereGeometry args={[size, 32, 32]} />
      <meshStandardMaterial color={color} />
    </mesh>
  );
};

export default Planet;
import { Canvas } from "@react-three/fiber";
import { OrbitControls, Stars } from "@react-three/drei";
import Planet from "./components/Planet";
import Sun from "./components/Sun";

// Sun component

const App = () => {
  return (
    <Canvas camera={{ position: [0, 20, 25], fov: 60 }}>
      {/* eslint-disable-next-line react/no-unknown-property */}
      <color attach="background" args={["#000000"]} />
      {/* eslint-disable-next-line react/no-unknown-property */}
      <ambientLight intensity={0.3} />

      {/* Added directional light for better illumination */}
      {/* eslint-disable-next-line react/no-unknown-property */}
      <directionalLight position={[5, 5, 5]} intensity={1} />
      <OrbitControls />
      <Stars radius={100} depth={50} count={5000} factor={4} />

      <Sun />
      <Planet
        position={[10, 0, 0]}
        size={1}
        color="#FF9A8C"
        orbitRadius={10}
        orbitSpeed={0.5}
      />
      <Planet
        position={[15, 0, 0]}
        size={1.2}
        color="#93C572"
        orbitRadius={15}
        orbitSpeed={0.3}
      />
      <Planet
        position={[20, 0, 0]}
        size={0.8}
        color="#22B5FF"
        orbitRadius={20}
        orbitSpeed={0.2}
      />
    </Canvas>
  );
};

export default App;

Note: We are using lots of components that are not imported, since we are using these component within the Canvas component which we imported from @react-three/fiber and it allow us to called and use these components.

Conclusion: This guide covers the essential basics of Three.js and provides a foundation for integrating it with Next.js. By understanding the core concepts and following best practices, you can create powerful and interactive 3D web applications. Once you grasp these concepts, we can move on to libraries like React Drei and React Three Fiber, which make it easier to implement Three.js in Next.js.

Related blog post on nextjs

  1. Mastering generateStaticParams() in Next.js 14: Boost Performance and SEO
  2. Understanding Nextjs Server Actions and Mutations 2024
  3. Understanding Routing in Next.js
  4. Understanding Prefetching in Next.js
  5. Data Fetching and Caching in Next.js 

Comprehensive Guide to Integrating Threejs in Nextjs

Leave a Reply

Your email address will not be published. Required fields are marked *

Scroll to top