I try to work with Marco Fugaro’s three-projected-material. I set my imports as follows:
import * as THREE from 'https://unpkg.com/three@0.122.0/build/three.module.js';
import { OrbitControls } from 'https://unpkg.com/three@0.122.0/examples/jsm/controls/OrbitControls.js';
import ProjectedMaterial, { project } from 'https://unpkg.com/three-projected-material';
But at the point I try to project the texture to a box (geometry and material defined well before):
const box = new THREE.Mesh(geometry, material);
project(box);
I get the following error message:
SyntaxError: The requested module 'https://unpkg.com/three-projected-material' does not provide an export named 'project'
although a function project is defined inside.
Can anybody explain how set it up correctly?
Thanx in advance for help.
bluefox67
(1) Keep in mind the repo was not updated for the past year - it uses three@0.111.0, while the version you are using is three@0.122.0 (it doesn’t mean it won’t work, just a thing to remember if stuff started to fail.)
(2) Importing:
https://unpkg.com/three-projected-material
redirects you to:
https://unpkg.com/three-projected-material@1.1.0/build/ProjectedMaterial.js
and results in importing this file. Since you’re using import
instead of <script>
tags, what you wanted to import is probably this file (source.) Try changing the import url to:
https://unpkg.com/three-projected-material@1.1.0/build/ProjectedMaterial.module.js
If I do so, I get the error
TypeError: Failed to resolve module specifier “three”. Relative references must start with either “/”, “./”, or “…/”.
Do you recommend to use tags instead of importing? In that case: Can I use the above URLs for THREE and OrbitControls, too?
As in the docs
:
<!-- Use <script> to import CDN files -->
<script src="//unpkg.com/three"></script>
<script src="//unpkg.com/three-projected-material"></script>
<script>
// Imported package exports everything to window.projectedMaterial
const { default: ProjectedMaterial, project } = window.projectedMaterial;
// Your code ...
</script>
I can’t test how it would work with script type="module"
for you atm, but since you’re using CDNs - doing imports with script tags may be the easier way.
Ok. Thanx so far. I’ll try. 
Causes next messages:
Uncaught ReferenceError: require is not defined
at three.js:1
(anonymous) @ three.js:1
three-projected-material:24 Uncaught TypeError: Cannot read property 'ShaderMaterial' of undefined
at three-projected-material:24
at three-projected-material:4
at three-projected-material:5
Sorry, it should be unpkg.com/three
instead of unpkg.com/three.js
(three.js leads to three.js/shim.js)
Edited the post above for clarity.
Ok. This is better. 
Just one more little thing: where are the OrbitControls located on unpkg.com?
unpkg inherits the structure from github repo. For example, this is the main three.js file:
https://unpkg.com/three@0.122.0/build/three.js
and OrbitControls are placed not in the build/
, but in examples/
directory (both in the repo and on unpkg) :
https://unpkg.com/three@0.122.0/examples/js/controls/OrbitControls.js
Fine. Now declarations are working without error messages 
But now, there is an error inside. I’ve loaded a texture image (png) and scaled the textureScale to 0.8 (as recommended in the example).
But there is an error saying:
Uncaught TypeError: Cannot read property 'naturalWidth' of undefined
at computeScaledDimensions (three-projected-material:194)
at new ProjectedMaterial (three-projected-material:56)
What’s wrong there?
Are you sure you did load it? The only place I can see in the ProjectedMaterial’s code that would throw that error - is when you pass a texture that hasn’t been loaded.
Yes, sure:
var texture = new THREE.TextureLoader().load('./test.png');
and
...
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new ProjectedMaterial({
camera, // the camera that acts as a projector
texture, // the texture being projected
color: '#cccccc', // the color of the object if it's not projected on
textureScale: 0.8, // scale down the texture a bit
cover: true, // enable background-size: cover behaviour, by default it's like background-size: contain
})
const box = new THREE.Mesh(geometry, material);
scene.add(box);
// and when you're ready project the texture!
project(box);
Did you try using a callback of TextureLoader.load (docs) ?
Texture loading is asynchronous, so just calling load
does not ensure that the texture exists right away. You can see in the texture loader source, that texture.image
is defined only after the image is actually loaded. Before that, texture image is set to Texture.DEFAULT_IMAGE (which, unless you changed it, is undefined.)
OK. Building this using a callback function
var texture = new THREE.TextureLoader().load(
// resource URL
'./test.png',
// onLoad callback
function ( texture ) {
// in this example we create the material when the texture is loaded
const material = new ProjectedMaterial({
camera, // the camera that acts as a projector
texture, // the texture being projected
color: '#cccccc', // the color of the object if it's not projected on
textureScale: 0.8, // scale down the texture a bit
cover: true, // enable background-size: cover behaviour, by default it's like background-size: contain
});
},
// onProgress callback currently not supported
undefined,
// onError callback
function ( err ) {
console.error( 'An error happened while loading texture.' );
}
);
const box = new THREE.Mesh(geometry, material);
I get an error for the last line:
Uncaught ReferenceError: material is not defined
.
It seems like this line will be reached before the callback is done …
Please keep in mind, three is probably not a good library to learn javascript with. It’s easier to first learn technicalities of js, and then jump to technicalities of three: