A brief introduction to three.js, where we’ll start by creating a scene with a rotating cube. At the bottom of the page, you’ll find a working example in case you get stuck and need help.
Installation
An easy-to-use, lightweight, cross-browser, general-purpose JavaScript 3D library for drawing and rendering 3D objects. Current builds include only the WebGL renderer, but WebGPU (experimental), SVG, and CSS3D renderers are also available in the examples.
You can install three.js using npm and modern build tools, or get started quickly using only static hosting or a CDN. For most users, installing via npm is the best choice.

Whichever option you choose, be consistent and import all files from the same version of the library. Mixing files from different sources can result in duplicate code being included or even cause unexpected errors in your application.
All methods of installing three.js rely on ES modules, which allow you to include only the necessary parts of the library in your final project.
Installation via npm
To install the npm three module (link), open a terminal window in your project folder and run the following command:
npm install three
The package will be downloaded and installed. You’ll then be ready to import it into your code:
// Option 1: Import the entire three.js core library.
import * as THREE from 'three';
const scene = new THREE.Scene();
// Option 2: Import just the parts you need.
import { Scene } from 'three';
const scene = new Scene();
When installing via npm, you’ll almost always use a tool to bundle all the packages your project needs into a single JavaScript file. While any modern JavaScript bundler can be used with three.js, the most popular choice is webpack.
Not all features are available directly through the three modules (this is called a “naked import”). Other popular parts of the library—such as controls, loaders, and post-processing effects—must be imported from the `examples/jsm` subfolder. To learn more, see the “Examples” section below.
Installation Using a CDN or Static Hosting
You can use the three.js library without any build system by uploading the files to your own web server or using an existing CDN. Since the library relies on ES modules, any script that references it must use type="module"as shown below. You must also define Import Map (an import map) that resolves the bare `three` module specifier.
<script async src="https://unpkg.com/es-module-shims@1.3.6/dist/es-module-shims.js"></script>
<script type="importmap">
{
"imports": {
"three": "https://unpkg.com/three@<version>/build/three.module.js"
}
}
</script>
<script type="module">
import * as THREE from 'three';
const scene = new THREE.Scene();
</script>
Since import maps are not yet supported by all browsers, you must add the es-module-shims.js polyfill.
Examples
The three.js core focuses on the most essential components of the 3D engine. Many other useful components—such as controls, loaders, and post-processing effects—are located in the examples/jsm directory.
They are called “examples” because, although you can use them as-is, they can also be customized and modified. These components are always kept in sync with the main library, whereas similar third-party packages on npm are maintained by different people and may be out of date.
The examples do not need to be installed separately, but they must be imported separately. If three.js was installed using npm, you can load the component OrbitControls using:
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
const controls = new OrbitControls( camera, renderer.domElement );
If three.js was installed from a CDN, use the same CDN to install other components:
<script type="module">
import { OrbitControls } from 'https://unpkg.com/three@<version>/examples/jsm/controls/OrbitControls.js';
const controls = new OrbitControls( camera, renderer.domElement );
</script>
It is important that all files use the same version. Do not import different examples from different versions, and do not use examples from a version that differs from the version of the three.js library itself.
Compatibility
CommonJS Import
Although most modern JavaScript components now support ES modules by default, some older build tools may not. In such cases, you can configure the bundler to understand ES modules: For example, Browserify only requires the babelify plugin.
Node.js
Since three.js is designed for the web, it relies on browser APIs and the DOM, which aren’t always available in Node.js. Some of these issues can be resolved using workarounds, such as headless-gl, or by replacing components like TextureLoader with custom alternatives. Other DOM APIs may be deeply intertwined with the code that uses them and will be more difficult to work around. We welcome simple and maintainable requests to improve Node.js support, but we recommend creating an issue to discuss your improvements first.
Be sure to add { "type": "module" } to your `package.json` to include ES6 modules in your Node.js project.
Checking WebGL Compatibility
Although this issue is becoming less and less relevant, some devices or browsers may still not support WebGL. The following method allows you to check whether it is supported and display a message to the user if it isn’t.
Add
https://github.com/mrdoob/three.js/blob/master/examples/jsm/capabilities/WebGL.js
this to your JavaScript and execute the following before attempting to render anything:
if ( WebGL.isWebGLAvailable() ) {
// Initiate function or other initializations here
animate();
} else {
const warning = WebGL.getWebGLErrorMessage();
document.getElementById( 'container' ).appendChild( warning );
}
Creating a Scene
Before you can use the three.js file, you need to render it somewhere. Save the following HTML to a file on your computer along with a copy of the three.js file in the js/ directory, and open it in a browser.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>My first three.js app</title>
<style>
body { margin: 0; }
</style>
</head>
<body>
<script src="js/three.js"></script>
<script>
// Our Javascript will go here.
</script>
</body>
</html>
That’s it. All the code below goes inside an empty <script> tag.
To be able to display anything using three.js, we need three things: a scene, a camera, and a renderer, so that we can display the scene through the camera.
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
const renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
Let’s briefly explain what’s happening here. We’ve now set up the scene, the camera, and the renderer.
There are several different types of cameras in three.js. For now, we’ll use PerspectiveCamera.
The first attribute is the field of view field of view (FOV). FOV is the area of the scene that is visible on the screen at any given moment. The value is expressed in degrees.
The second is the aspect ratio aspect ratio. You should almost always use the element’s width divided by its height; otherwise, you’ll get the same result as when playing old movies on a widescreen TV—the image will look squished.
The next two attributes are the near (near) and far (far) clipping planes. This means that objects located farther from the camera than the value far, or closer than near, will not be rendered. You don’t need to worry about this right now, but you may want to use different values in your applications to improve performance.
Next comes the renderer. This is where the magic happens. In addition to the WebGLRenderer we’re using here, three.js comes with several others, often used as fallback options for users with older browsers or for those who, for whatever reason, lack WebGL support.
In addition to creating an instance of the renderer, we also need to specify the dimensions at which we want it to display our application. It’s a good idea to use the width and height of the area we want our application to fill—in this case, the width and height of the browser window. For applications that require high performance, you can also specify setSize smaller values, such as window.innerWidth/2 and window.innerHeight/2, which will cause the application to render at one-quarter of its normal size.
If you want to keep your app’s size but display it at a lower resolution, you can do so by calling setSize with false as updateStyle (the third argument). For example:
setSize(window.innerWidth/2, window.innerHeight/2, false)
will render your app at half the resolution, assuming your <canvas> has 100% width and height.
Last but not least, we add an element renderer to our HTML document. This is the:
“That’s all well and good, but where’s the promised cube?”
Let’s add it now.
const geometry = new THREE.BoxGeometry( 1, 1, 1 );
const material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
const cube = new THREE.Mesh( geometry, material );
scene.add( cube );
camera.position.z = 5;
To create a cube, we’ll need BoxGeometry. This is an object that contains all the points (vertices vertices) and the fill (faces faces) of the cube. We’ll cover this in more detail later.
In addition to the geometry, we need a material to color it. Three.js comes with several materials, but for now we’ll stick with MeshBasicMaterial. All materials accept an object of properties to be applied to them. To keep things very simple, we’ll provide only a color attribute 0x00ff00—specifically, green. This works the same way colors do in CSS or Photoshop (hex colors hex colors).
The third thing we need is a mesh Mesh. A mesh is an object that takes geometry and applies a material to it, which we can then place in our scene and move around freely.
By default, when we create scene.add(), the object we add will be placed at the coordinates (0,0,0). This will cause the camera and the cube to end up inside each other. To avoid this, we’ll simply move the camera out a little.
Rendering the Scene
If you copy the code above into the HTML file we created earlier, you won’t see anything. That’s because we haven’t rendered anything yet. To do this, we need what’s called a rendering or animation loop (render or animate loop).
function animate() {
requestAnimationFrame( animate );
renderer.render( scene, camera );
}
animate();
This will create a loop that forces the renderer to draw the scene every time the screen is refreshed (on a standard screen, this means 60 times per second). If you’re new to browser game development, you might ask, “Why don’t we just create setInterval?».
The thing is, we could, but requestAnimationFrame it has a number of advantages. Perhaps the most important of these is that it pauses when the user switches to another browser tab, meaning it doesn’t waste precious processing power or battery life.
Cube Animation
If you paste all the code above into the file you created before we started, you should see a green square. Let’s make it a little more interesting by rotating it.
Add the following code right above the call to renderer.render in your function animate:
This loop will run every frame (usually 60 times per second) and give the cube a nice rotation animation. Basically, anything you want to move or change while the app is running should go through the loop animate. Of course, you can call other functions from there so you don’t end up with a function animateconsisting of hundreds of lines.
Result
Congratulations! You’ve finished building your first three.js app. It’s simple, but you have to start somewhere.
The full code is available below and as an editable live demo. Play around with it to better understand how it works.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>My first three.js app</title>
<style>
body { margin: 0; }
</style>
</head>
<body>
<script src="js/three.js"></script>
<script>
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
const renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
const geometry = new THREE.BoxGeometry( 1, 1, 1 );
const material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
const cube = new THREE.Mesh( geometry, material );
scene.add( cube );
camera.position.z = 5;
function animate() {
requestAnimationFrame( animate );
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render( scene, camera );
};
animate();
</script>
</body>
</html>
How to Run Things Locally
If you’re only using procedural geometries and aren’t loading any textures, web pages should work directly from the file system—just double-click the HTML file in your file manager, and it will open in your browser (you’ll see `file:///yourFile.html` in the address bar).
Content loaded from external files
If you load models or textures from external files, due to security restrictions imposed by the same-origin policy in browsers, loading from the file system will result in a security exception error.
To resolve this issue, serve the files from a local web server. This allows you to access your page as:
http://localhost/yourFile.html
Although you can also change your browser’s security settings instead of running a local server, we do not recommend this approach. This solution could expose your device to vulnerabilities if the same browser is used for regular web browsing. Using a local server is standard practice in web development, and below we’ll explain how to set up and use a local server.
Running a Local Server
Many programming languages have built-in simple HTTP servers. They aren’t as feature-rich as production servers like Apache or NGINX, but they should be sufficient for testing your three.js application.
Plugins for Popular Code Editors
Some code editors have plugins that can set up a simple server on demand.
- Five Server for Visual Studio Code.
- Live Server for Visual Studio Code.
- Live Server for Atom.
Servez
Servez is a simple server with a graphical user interface.
Node.js five-server
A development server with real-time reloading. To install:
# Remove live-server (if you have it)
npm -g rm live-server
# Install five-server
npm -g i five-server
# Update five-server (from time to time)
npm -g i five-server@latest
To run (from the local directory):
five-server . -p 8000
Node.js http-server
Node.js includes a simple HTTP server package. To install:
npm install http-server -g
To run (from the local directory):
http-server . -p 8000
Python server
If you have Python installed, simply run it from the command line (from the working directory):
//Python 2.x
python -m SimpleHTTPServer
//Python 3.x
python -m http.server
This will serve files from the current directory on localhost at port 8000; that is, enter the following in the address bar:
http://localhost:8000/
Ruby Server
If you have Ruby installed, you can achieve the same result by running this program:
ruby -r webrick -e "s = WEBrick::HTTPServer.new(:Port => 8000, :DocumentRoot => Dir.pwd); trap('INT') { s.shutdown }; s.start"
PHP Server
PHP also has a built-in web server, starting with version 5.4.0:
php -S localhost:8000
Lighttpd
Lighttpd is a very lightweight, general-purpose web server. Here, we’ll cover how to install it on OS X using HomeBrew. Unlike the other servers discussed above, Lighttpd is a full-fledged server that’s ready to go.
1. Installing via HomeBrew
brew install lighttpd
2. Create a lighttpd.conf configuration file in the directory where you want to run your web server. A sample can be found here.
3. In the conf file, change server.document-root to the directory from which you want to serve files.
4. Start with:
lighttpd -f lighttpd.conf
5. Go to http://localhost:3000/, and it will serve static files from the directory you selected.
IIS
If you are using Microsoft IIS as your web server, please add MIME type settings for the .fbx extension before uploading.
File name extension: fbx MIME Type: text/plain
By default, IIS blocks uploads of .fbx and .obj files. You’ll need to configure IIS so that these files can be uploaded.
Other simple alternatives can be discussed on Stack Overflow here.