Toby Gates.
Creating a 3D starfield effect with React & Three

Creating a 3D starfield effect with React & Three

By Toby Gates - 19 February 2021


Introduction

In this article we are going to explore how to create a component with a 3D starfield type effect similar to the one on the homepage using React and Three.js.

Below is a demo of what we'll be building:

Demo:

Setting up the basic component

Before we get started on the component we'll need to install a few packages. The packages we'll be using are three, @react-three/fiber and @react-three/drei.

  • three (Three.js) is an easy to use, lightweight, 3D library with a default WebGL renderer.
  • @react-three/fiber is a React renderer for Three.js.
  • @react-three/drei is a collection of useful helpers and abstractions for @react-three/fiber.

We can install these packages as follows:

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

Once the packages have been installed we're ready to create our component.

We'll start off with a basic React functional component and import the modules we need.

Then we need to include the Stars element from @react-three/drei and wrap it in the Canvas element from @react-three/fiber.

Code:

import React from 'react'
import { Canvas } from '@react-three/fiber'
import { Stars } from '@react-three/drei'

const Starfield = () => {
  return (
    <div className='stars'>
      <Canvas>
        <Stars />
      </Canvas>
    </div>
  )
}

export default Starfield

This provides us with a very basic version of the starfield effect we are looking for.

Demo:

Note: For the sake of the demo, we've also add a background, height & margin so that the element is visible.

Animating the component

Next we need to look at how we can animate the component.

Let's setup a new functional component called RotatingStars to return the Stars component we imported earlier, and use it to replace the Stars component wrapped in the Canvas.

Code:

import React from 'react'
import { Canvas } from '@react-three/fiber'
import { Stars } from '@react-three/drei'

const RotatingStars = () => {
  return <Stars />
}

const Starfield = () => {
  return (
    <div className='stars'>
      <Canvas>
        <RotatingStars />
      </Canvas>
    </div>
  )
}

export default Starfield

Now that Stars is wrapped in it's own component, we are able to manipulate that element.

The useFrame hook provided by @react-three/fiber will allow us to hook the component into the render-loop.

We will also need a way of letting React know which element we'll be animating so we'll need to import the useRef hook.

import React, { useRef } from 'react'
import { Canvas, useFrame } from '@react-three/fiber'
import { Stars } from '@react-three/drei'

In our RotatingStars function, let's create a ref and attach it to the Stars component.

const RotatingStars = () => {
  const stars = useRef()

  return <Stars ref={stars} />
}

Now we have a reference to the element we can update its rotation on each render of the render-loop using the useFrame hook.

const RotatingStars = () => {
  const stars = useRef()

  useFrame(() => {
    stars.current.rotation.x = stars.current.rotation.y += 0.00015
  })

  return <Stars ref={stars} />
}

Here we've set the x rotation to be slightly offset from the y rotation - giving us the slow spinning effect.

You should now have something that looks like this:

Code:

import React, { useRef } from 'react'
import { Canvas, useFrame } from '@react-three/fiber'
import { Stars } from '@react-three/drei'

const Starfield = () => {
  const RotatingStars = () => {
    const stars = useRef()

    useFrame(() => {
      stars.current.rotation.x = stars.current.rotation.y += 0.00015
    })

    return <Stars ref={stars} />
  }

  return (
    <div className='stars'>
      <Canvas>
        <RotatingStars />
      </Canvas>
    </div>
  )
}

export default Starfield

Demo:

Movement Controls

On the version on the homepage there is a button to allow a '3D orbit' type effect. This can be achieved using OrbitControls component included in the @react-three/drei package.

It's simply a matter of importing the component and wrapping it within the Canvas component.

import { Stars, OrbitControls } from '@react-three/drei'
return (
  <div className='stars'>
    <Canvas>
      <OrbitControls />
      <RotatingStars />
    </Canvas>
  </div>
)

This gives us the orbit controls as shown in the demo below:

Demo:

Note: The 'Explore Space!' button on the homepage toggles an orbit state which in turn toggles the OrbitControls component on and off.

Conclusion

Hopefully this article has given you a brief understanding of how to setup a very basic @react-three/fiber component while also creating a fun effect that you can use in your projects.