Importing Orbit Controls from local files

Hi! I am having a struggle trying to import orbit controls, I have downloaded all the three files on my laptop in this structure:


And this is my code for importing (from file) the orbitcontrols.js and calling the setting the controls function:

And I get the following error:

“Uncaught TypeError: THREE.OrbitControls is not a constructor”

Any ideas please?

All I see are examples of importing from npm and cdn and I think I’m not using either (just importing from the download file on my laptop). Am I right? I’m new to three.js and java so any hint could help :slight_smile:

JS without npm makes little sense, you can’t just have an html click on it, nor can you consume npm packages. You need a bundler, preferably vite because it’s super easy to use.

Install node, there’s no JavaScript without node, open shell, type: npm create vite

There are several versions of OrbitCntrols. If you want to load it locally, it depends on whether it is the module or non-module version of the file. Non-module version should have no problems. The module version would require a local webserver.

Sorry, but this a very limited view of web development. Developing JS without the need for a tool chain is what the web makes so accessible. Of course the mentioned node.js, npm and bundlers are important tools but especially beginners do not necessarily need them if they want to learn a library or just want to experiment with code.

@Ana_Hernandez_Guardiet You have to understand that downloading libary files and putting them into custom directories is no recommended workflow in JavaScript anymore. This was done in earlier days but now with a real module system you do it differently.

The three.js project recommends two workflows:

  • You install node.js/npm on your system and install three.js as a dependency of your project. You also rely on a bundler like rollup, vite, parcel or webpack that produces a build of your app. This is the recommended workflow for any kind of professional work however it requires a lot of knowledge in different tools.
  • For beginners or devs who just want to learn three.js and experiment with the code, it’s easier to get started by importing files from a CDN. I recommend your use this workflow for now since you can easier start having fun with three.js. Your code would look like so then:
<!-- Import maps polyfill (With latest Chrome or Firefox, you don not need this anymore ) -->
<script async src=""></script>

<script type="importmap">
		"imports": {
			"three": "",
			"three/addons/": ""

<script type="module">

	import * as THREE from 'three';
	import { OrbitControls } from 'three/addons/controls/OrbitControls.js';

	// later in your code

	const controls = new OrbitControls( camera, renderer.domElement );

Like with the official examples, you need an import map first that you include into your HTML. Next, the three.js library as well as OrbitControls are imported with a more modern style called ES6 imports. And when creating the instance of OrbitControls, you don’t need the THREE namespace.

You find more information about this topic in the official Installation guide.

BTW: Static hosting of three-js is also fine but in this case you should host the entire repository and not individual files in custom directories. In this way, you preserve the original file structure and don’t break things.


I typically agree and respect your knowledge and usage of react/three but this statement is very misleading and not true.

the OP is not asking for a way to consume npm packages, although I understand your personal application of using node and react I think you may be confusing new users of three who look at the three.js examples and documentation. Don’t get me wrong I really love and respect the work you do but I think the clarity between these two different approaches of using the library needs to be preserved…

@Ana_Hernandez_Guardiet you will need to import orbit controls through import maps if using the latest versions of three.js in your approach, @Mugen87 has answered your question in detail while typing this…

1 Like


@drcmda Don’t get me wrong, you work in the React space is great but I’m not fan of how you try to push users into your preferred workflow. There are many ways of using three.js and all are valid. Pushing users into a too specific development pattern is not good for the user and three.js in general.


making a beginner use unfinished, complicated browser specs, script tags, import maps, module shims, fragile cdns with outages, you forgot telling them to install phyton and an HTTP server, … , … :face_with_spiral_eyes:

or, vite, ready under 5 seconds, the whole wide world uses it, they can go about their day and code.

ps this is also the very first lesson in threejs journey (installing vite), it’s free btw: Three.js Journey — Local Server

i’m guessing bruno simon is also “pushing users” and “not good for threejs”. all sillyness aside, that this is not taught on the threejs website front and center is pretty awful in my opinion. anyway, i wasn’t aware it was free, i’m going going to link that from now on instead.

in all fairness and at the cost of going completely off topic, nothing you wrote addresses the OP’s original question.

would you say this is a valid anser on how to import orbit controls from local files?
“using node and npm you can import orbit controls in the following way…” may have been.

without causing any offence or upheaval, it seems you’re undermining the countless contributing developers approach and agreement on efficient coding practices in building and maintaining a very stable and accessible cross platform 3D library for the web. Would you say that your preffered way of accessing libraries such as three.js is more valid than all the developers and contributors who follow and agree on a certain code implementation to achieve this?

Although i don’t know this for certain i can imagine the future of browser specifications are likely taking a lot of pointers in terms of the way libraries like three.js are constructed, as to become more like a “bundler” in themselves at runtime.

As far as three’s site and docs being confusing for you, they seem to be and have been perfectly stable and accessible for pretty much every use case neccissary throughout the entirity of the development of the library, including being bundled and tree shaken as you suggest…

In all it’s entirety, threejs is open source to be completely inclusive of constructive suggestions and efficient solutions to the problems you have personally experienced and are outlining, i’m 100% sure that your input on creating PR’s that follow the common workflow of the library for these issues would be accepted with open arms as to the knowledge you offer…

i hope you’re having a good weekend so far, it’s all love.

if i see that what they’re attempting is confused, i much rather invest some time into best practices.

they’ll be here tomorrow, the “solution” doesn’t allow loading a model. tomorrow you’ll tell em to install phython and a HTTP server. and this will go on, deeper into a rabbit hole until they give up, because no one bothers to engage. threejs discourse is mostly people struggling with the simplest fundamentals because they’re getting pushed into unreasonable practices.

as for the threejs website, suggesting unfinished specs, import maps, shims and http servers is incomprehensible. this is not just confusing, it is damaging.

or just use in browser tools meant for this and run the development folder from inside chrome locally…?

you’ve edited your answer but i’d dissagree that bundling would be considered “best practice” as this is subjective and is completely dependent on the use case of any application, a client paying top dollar for a web optimized production build sure, a demonstrative repo that allows people to see how classes are used together to create a custom environment to learn and have some fun with not so much, afaict, bundling is there to reduce the amount of HTTP requests per build… the resources i personally found on this subject suggest that…

HTTP/2 no longer has bi overhead when making multiple HTTP requests, therefore, there’s no advantage to bundling everything up. Changes to the bundle invalidates the cache forcing users to download everything again. HTTP/2 is supported by 95% of clients worldwide, so we can assume that we don’t need to bundle everything together.

so again bundling is completely subjective based on the particular use case…

we’d be turning in circles. as i said, you’re telling em to install more tools now. but the problem tomorrow-tomorrow will be 3rd party packages, then they want to publish, but the site’s 10mb, and so on and so on and so on. rinse and repeat, this is basically discourse.

what you quoted is years outdated. modern “bundlers” like vite use plain esm, they don’t “bundle” as tools 5 years ago did, they ship single http/2 modules. but they minify and tree-shake. the project you upload only contains the code you actually use.

i think it’s fine, i recognise you just want to help. i wanted to do the same, and i have a way to come across as overly harsh, unwittingly i might add.

not at all, as i say, i think the work you do and contributions you make are amazing and some of the finest usages out there.

I just think the key to three’s accesibility is allowing any user to apply their own knowledge of js to use the library in a way that suits their needs and i think it’s magical that the amount of knowledge on the forum can address issues even under the most outdated and clunky usage of the library, a vast amount of users are just experimenting, come from old school versions of js and / or are completly new to the world of 3D online and yes likely they will eventually need to create production builds that need optimising with tree-shaking and minification but i think that’s also part of the journey and magic of learning a library like three is that it’s community IS all encompassing on these matters and feilds of knowledge

I have assumed the OP uses the live server of VSCode.

@drcmda I was already afraid when writing my initial post that the discussion here would end up in a back-and-forth. Again. If I had more energy and time I would respond to some of your questionable statements. But I can’t. It’s simply too exhausting.

I’m gonna close this thread since it went off-topic and the contents are not really helpful to readers anymore.