(1y ago)
Let's make a cool 3D webpage using Three-js in Next.js 13.
Start off with creating a new Next-js
project with app-dir and install three-js.
Here i am using JS
, tailwindCSS
and Next-js 13.2
with app-directory.
npx create-next-app@latest
npm i three
/app/page.js
and clean up the starter code.Three.js
component file in /app
director y (/app/Three.js
).Three.js
is the file where we will be writing our three-js
code.populate /app/Three.js
with the following starter code.
export default function Three() {
return <>Three-js code goes here</>
}
go ahead and import this component in /app/page.js
.
import Three from './Three'
export default function Home() {
return <Three />
}
Note:
In the next following steps you will be editing /app/Three.js
file.
You can think of your 3D scene as a movie shooting session. Where you are required to have a camera, a scene and film in the camera to capture the movie. Similarly here in Three-js you need a camera
, a scene
and a renderer
. We need to create these three things.
populate /app/Three.js
page with the following code that sets up our scene
in three-js.
'use client'
import React, { useRef, useEffect } from 'react'
import * as THREE from 'three'
export default function Three() {
const sceneRef = useRef(null)
const cameraRef = useRef(null)
const rendererRef = useRef(null)
useEffect(() => {
sceneRef.current = new THREE.Scene()
cameraRef.current = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
)
rendererRef.current = new THREE.WebGLRenderer({ antialias: true })
}, [])
return <>Three-js cool.</>
}
In the following code block you are rendering your 3D geometry as soon as you load the page. This is achieved by useEffect()
hook. In this hook call you are setting the renderer's size viz, window.size
and pushing the 3D object to the end of the page.
'use client'
import React, { useRef, useEffect } from 'react'
import * as THREE from 'three'
export default function Three() {
const sceneRef = useRef(null)
const cameraRef = useRef(null)
const rendererRef = useRef(null)
useEffect(() => {
sceneRef.current = new THREE.Scene()
cameraRef.current = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
)
rendererRef.current = new THREE.WebGLRenderer({ antialias: true })
}, [])
// New Code Here
useEffect(() => {
const scene = sceneRef.current
const camera = cameraRef.current
const renderer = rendererRef.current
renderer.setSize(window.innerWidth, window.innerHeight)
document.body.after(renderer.domElement)
}, [])
return <></>
}
The simplest geometry in three-js is a ball i.e; SphereGeometry.
Sphere geometry takes a bunch of parameters in it's constructor while creating it. Explore around the documentation here to figure out how you can customize your Ball.
The following code creates a Ball and adds it to the scene.
const geometry = new THREE.SphereGeometry(15, 32, 16)
const material = new THREE.MeshBasicMaterial({ color: 0xffff00 })
const sphere = new THREE.Mesh(geometry, material)
scene.add(sphere)
Now for the final step you can copy the following code block to your /app/Three.js
file and run npm run dev
.
'use client'
import React, { useRef, useEffect } from 'react'
import * as THREE from 'three'
export default function Three() {
const sceneRef = useRef(null)
const cameraRef = useRef(null)
const rendererRef = useRef(null)
useEffect(() => {
sceneRef.current = new THREE.Scene()
cameraRef.current = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
)
rendererRef.current = new THREE.WebGLRenderer({ antialias: true })
}, [])
useEffect(() => {
const scene = sceneRef.current
const camera = cameraRef.current
const renderer = rendererRef.current
renderer.setSize(window.innerWidth, window.innerHeight)
document.body.after(renderer.domElement)
// New Code Here
const geometry = new THREE.SphereGeometry(15, 32, 16)
const material = new THREE.MeshBasicMaterial({ color: 0xffff00 })
const ball = new THREE.Mesh(geometry, material)
scene.add(ball)
const animate = () => {
requestAnimationFrame(animate)
renderer.render(scene, camera)
}
animate()
}, [])
return <></>
}
And That's It Folks now you have a ball on your screen.
Fun-Note
you can wrap your ball with any picture to make it look cool. Or make it look like a planet or a star or anything that comes to your imagination. Let's make a moon 🌚,
you can get the 🌚 jpg
from here.
'use client' import React, {(useRef, useEffect)} from
'react' import * as THREE from 'three'
export default function Three() {
const sceneRef = useRef(null)
const cameraRef = useRef(null)
const rendererRef = useRef(null)
useEffect(() => {
sceneRef.current = new THREE.Scene()
cameraRef.current = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
)
rendererRef.current = new THREE.WebGLRenderer({ antialias: true })
}, [])
useEffect(() => {
const scene = sceneRef.current
const camera = cameraRef.current
const renderer = rendererRef.current
renderer.setSize(window.innerWidth, window.innerHeight)
document.body.after(renderer.domElement)
// New Code Here
const moonImg = 'https://tinyurl.com/spj4rujm'
const ball = new THREE.Mesh(
new THREE.SphereGeometry(10, 150, 20),
new THREE.MeshBasicMaterial({
map: new THREE.TextureLoader().load(moonImg),
})
)
scene.add(ball)
const animate = () => {
requestAnimationFrame(animate)
// Rotating the Moon around it's own axis
ball.rotation.x += 0.01
renderer.render(scene, camera)
}
animate()
}, [])
return <></>
}
That's it For Now folks. Maybe in not so far future i might make a something like npx create-next-three
.
Good Day 🐼