Cells in Observable are evaluated in topological order, not top-down order, so if you require Three.js, any cell that references it (THREE
) will automatically wait until it has been loaded. Here’s a quick hello-world:
https://beta.observablehq.com/@mbostock/hello-three-js
If a library is defined as an AMD or an ES module, then library dependencies are loaded automatically. For example, if you require d3-scale:
d3 = require("d3-scale")
This will also cause d3-array, d3-collection, d3-format, d3-interpolate, d3-time and d3-time-format to be loaded. If you are a library author, I recommend using Rollup to bundle your library. It lets you declare your dependencies in the package.json and supports AMD, UMD, IIFE and ES module bundle formats.
While Three is defined in the UMD format, Three OrbitControls are not, so you have to jump through another hoop to load them. The OrbitControls module is CommonJS: it depends on a global module.exports, which it assigns to a function. You need to call this function in order to create the OrbitControls object. Here’s what I recommend:
THREE = {
const THREE = await require("three@0.82.1/build/three.min.js");
if (!THREE.OrbitControls) { // If not previously loaded.
const module = window.module = {exports: undefined};
THREE.OrbitControls = await require("three-orbit-controls@82.1.0/index.js").catch(() => module.exports(THREE));
}
return THREE;
}
This code is extra tricky because require
is cached internally, so we have to be careful to not try to load OrbitControls more than once. Here’s a working demonstration:
https://beta.observablehq.com/@mbostock/hello-three-js-orbit-controls