The examples/js directory will be removed with r148

three.js is going to remove its examples/js directory in the next release r148. That means addons like GLTFLoader or OrbitControls will only be available as ES6 modules in the examples/jsm directory.

What does that mean for me?

If you are already using ES6 modules, it won’t be necessary to update your workflow. Only if you are using the third-party libraries ammo.js, Draco or Basis from the repository, you will have to update your import paths e.g. from /examples/js/libs/draco to /examples/jsm/libs/draco/.

If you are importing files from examples/js via the <script> tag, a bigger migration task is required.

Migrating to ES6 modules

We recommend to use one of the popular build tools like rollup or Webpack since they all support ES6 modules for quite a while now. Using this workflow means you are going to install three.js via npm and import the core and addons from the respective package. If you don’t want to use a build tool for whatever reasons, you can import three.js from a CDN or via static hosting (e.g. your own web server).

Both import strategies are explained in more detail with code examples in the Installation guide.


We have decided to remove examples/js since the respective files conform to no JavaScript Module standard. This fact has many negative consequences for the developer experience. It’s error-prone to import files with complex dependencies, you can’t properly use build tools with their optimizations (e.g. tree shaking) and you end up with different imports depending on which environment you are developing (browser, node etc.). Existing resources in the web explain even more more counterpoints in not using modern module syntax.

With ES6 modules, developers can rely on a future-proof standard which is now properly supported in the JavaScript ecosystem.


I’ve already received a message from someone that is using a link like this:

The quickest way to fix these is by replacing dev with r147:

But I would recommend using unpkg instead:

this has a chance of going out of sync if they do not also lock GLTFLoader, no? or do they just use draco itself :thinking: then why not their own repo :face_with_raised_eyebrow:

Users are advised to always use a version qualifier in their CDN URLs. And only include three.js sources from the same release.

Heh, i thought both js and jsm examples would be removed :frowning:

About time

Well for those few of us that want or need to stay with es5. Is there someway to convert to es5? Isn’t there some program that can do that?

1 Like

Ha, wouldn’t that be basically removing the whole library?! Oops

git rm -r *


you mean like babel?

Not sure why you’d want this but you could give it a go with babel, getting used to es6 would definitely benefit your workflow, especially with three.js, you can still integrate libraries that are written in es5

Yes I think thats what I have heard of. Is it easy to use?

Look guys, I know es6 is best, I don’t disagree, its just I have been working on a project for over 8 years now with es5 and its huge and don’t want to have to rewrite is all right now. Once I release if it & if it goes well, then redoing in es6 and from what I can see use React seem to be perfect options, but at least for now I need to stay with es5

everything is easy to use once you set it up :slight_smile: basically it is an extra step in your build process that can downgrade all your code to older javascript. you could probably set it up to run on 3js repo, too, if you are not doing any building in your project.

1 Like

No the library is in /src examples are just what people wrote over time. I think the problem is more that examples are “how to do graphics stuff” vs “how to use this class in the library”.

Also, for people using es5 and such, why can’t you just use versions up to 147?

setting up babel to transpile the code back to es5 imo wouldn’t be straight forward, for starters babel won’t create IIFE’s.

import foo from "foo";

turns into

"use strict";

function _interopRequireDefault(obj) {
  return obj && obj.__esModule ? obj : { default: obj };

var _foo = _interopRequireDefault(require("foo"));

you’d need something that defines “require” but the point is, these are still modules. there is an unofficial plugin for iife but it’s years old. another option would be to use rollup, which definitively can output iife’s. but tbh, this all just looks like weekends wasted on beating a dead horse to me.

i’d also suggest pinning 147 and using that for the forseeable future.

1 Like

Well ok, thought babel might be an option, but if not I can live with 147. It’s a lot further than ver 90 that I was at when I picked this project back up.

Thanks guys

One of the best features of Three.js has been the lack of any setup. You can just include and get the latest version. No version management, no build, no modules, npm or other stuff needed for a quick project. The exception is that OrbitControls needs another file to be imported.

Won’t this change, that now requires the user to worry about modules, local servers or whatnot, be an additional (however slight) barrier for entry for using something as useful as camera controls?

Are there plans to include orbit controls and other useful things in the examples folder (or similar functionality) in the core JS code to minimise the setup cost of small projects (for example on CodePen or in classrooms)?

1 Like

Be aware that this is no recommended workflow. Blindly using the latest version of a library can easily break your app/website since a release can contain breaking changes and thus require migration tasks. You should always develop and test your app/website with a fixed set of dependencies. Besides, is no CDN.

I don’t think so since you essentially do the same as before. You import the core and and a additional control class. You are just using modules which means a different import syntax. And you can still use CDNs.

No. We do not consider importing addons as additional setup costs.

1 Like

Dear mrdoob, thank you for posting my question here.
Your answer is quite understandable and clear.
I found this loader somewhere on stackoverflow, so without much thought I used the links to GitHub. The team decided to leave links to an external resource, and not use it locally.

Why is this an exception?

If one is not using any camera navigation and their app is rendering a static view (maybe a full screen quad) they may not need OrbitControls :thinking:

On the other hand, if one wants TransformControls they will need to import two additional files? Maybe more… so this is not the only exception. Some users may have more others may not even run into this as an exception.

Consider this - you are not the only user of three.js, there are others. Thus, there exist many different use cases. Some may not need OrbitControls at all. Some may not find those “other useful things” at all useful. Why would they have all of this cruft embedded in the library that they use?

One should use a template/boiler plate, and do this setup once. Also, i think that using a javascript library in isolation is not the best approach to teaching. Three is often not the only library needed to make a website/app. stats.js is a completely stand alone package that is often used with three.js apps. My suggestion would be to include multiple files, and then at some point explain to students how that works.