9:1 Getting Started with three.js

Getting started with three.js is not hard. But you have to do a few more things yourself than you might be used to.

There is a bit less magic than in P5JS. P5JS has a setup function that automatically gets run once, and a draw function that automatically gets fired on each browser animation frame. With three.js you need to do that bit yourself, but once you get used to that you'll find you're actually digging deeper and learning how it all works.

A three.js starter

Lets play with a simple three.js project. There are a lot of different ways of setting up a three.js project. There's no right or wrong way, and the three.js Manual sets out some options here.

This starter code tries to be as minimal as possible so we can concentrate on whats happening.

In this example you can see that the index.html is very simple. It is only included to show you that there's very little to it. The one line that does all the work is:

<script type="module" src="/sketch.js"></script>

type="module" in this code loads the JavaScript file as a module - this is a more modern and powerful way of using JavaScript than you might be used to. It enables a JavaScript file to load other JavaScript files, this creates a powerful modular way of using code.

In the sketch.js file three.js is imported directly from a CDN (Content Delivery Network - just a really fast way of loading files)

import * as THREE from "https://cdn.jsdelivr.net/npm/three@0.184.0/build/three.module.js";

This is the latest version of three.js (it gets updated frequently so this might lag behind, but i'll updated this code regularly). Now we've imported three.js we have access to all its functions via the THREE object.

Now we create the scene, camera, and renderer

  • The scene holds all of our 3D objects, we will add things to it later
  • The camera is what we view the scene with, we can change its properties, move it etc if we want.
  • The renderer is the engine that understands the scene and the camera and draws it all to the canvas so we can see it.

Now we create something to put in the scene, in this case a cube. To make that cube we need geometry:

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

and material:

const material = new THREE.MeshNormalMaterial();

We then use both of these to make a MESH, and add it to the scene

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

All of this code would be equivalent to setup() in p5JS, it will run once. But we also want to animate and by virtue of animation we can have interactivity too as this will respond to changes. The browser has a built in method to animate very efficiently via requestAnimationFrame() so we use this to make an animation loop:

function animate() {
  shape.rotation.x += 0.005;
  shape.rotation.y += 0.01;

  // render the scene, then schedule the next frame (~60fps)
  renderer.render(scene, camera);
  requestAnimationFrame(animate);
}

animate();

This code is a function called animate() that we create to do everything we want to update on each frame.

The shape variable inherits lots of functions and properties from THREE.Mesh so in this instance we update its rotation.

Each time something changes we need to tell the renderer of these changes so renderer.render(scene, camera) is called on every frame.

The last thing we do is call requestAnimationFrame(animate) which tells the browser to run animate() again in a very efficient way that waits till the next frame. (this is all explained in the three.js manual in more detail!)