Shape made from BufferGeometry not casting/receiving shadows when other shapes are

Hello, new to three.js (but not to 3D programming) and generally loving it! I’m creating a cube in my own custom shape class using BufferGeometry, and everything works as expected when I add it to my scene except that it doesn’t cast/receive shadows despite my setting castShadows and receiveShadows to true. Other shapes in my scene, both those imported from obj files or created using the built-in box primitive, cast and receive shadows fine. I’ll attach a screenshot and you can see the orange taller cube not casting or receiving shadows. I tested the material I’m using for it on a regular box primitive and it worked fine too, so I know it’s not an issue with the material. I tried setting castShadows on both the geometry and the mesh, and I tried having it calculate bounding box/sphere in case that was it, to no avail. Here’s my code creating the BufferGeometry:

var vertexArray = new Array();

vertexArray.push(-width, 0, width);
vertexArray.push(width, 0, width);
vertexArray.push(width, height, width);
vertexArray.push(-width, height, width);
vertexArray.push(-width, 0, -width);
vertexArray.push(width, 0, -width);
vertexArray.push(width, height, -width);
vertexArray.push(-width, height, -width);

var faceIndexBuffer = new Array();
for (const ff of TowerSquare.faceIndices) {
	faceIndexBuffer.push(ff.x);
	faceIndexBuffer.push(ff.y);
	faceIndexBuffer.push(ff.z);
}

let geometry = new THREE.BufferGeometry();
geometry.setIndex(faceIndexBuffer);

this.vertexBuffer = new Float32Array(vertexArray);
geometry.setAttribute(
	"position",
	new THREE.BufferAttribute(this.vertexBuffer, 3)
);
geometry.computeVertexNormals();
//geometry = geometry.toNonIndexed();
geometry.castShadows = true;
geometry.computeBoundingBox();
geometry.computeBoundingSphere();
//geometry.computeTangents();

this.mesh = new THREE.Mesh(geometry, TowerSquare.orangeMaterial);
this.mesh.castShadows = true;

And image:

needs to be .castShadow (without s at the end) :thinking:

1 Like

Oh wow, that’s it, THANK YOU! Frankly I had no idea javascript would allow me to make such an error without any warnings (I’m coming from C++), seems a bit of a disaster in the language, but now I’ll know to watch out for that and go find out how people deal with being able to assign any random variable name in a class to anything…

1 Like

Yup get used to it, and get used to checking things in the debugger. :smiley:
Welcome to javascript! Also… using an IDE with autocomplete can help catch these things…

2 Likes

Welcome to the wonderful world of JS :handshake: :sweat_smile:

2 Likes

Haha thanks guys. I did a bit of research and I think “use strict” and preventExtensions will get me mostly there :rofl:

1 Like

You’re probably looking for typescript.

So far I’ve opted against that because I don’t like having to “compile” and upload a different file than the one I’m actually working on. But I’m a noob to web programming so it’s possible there are several pieces that I don’t get yet that would make me go with typescript in the end. I like to have absolutely as few dependencies, setup, and intermediate steps as possible. I’ve been stoked to be able to use three.js with nothing but vanilla vs code and cdn imports (though still learning the ins and outs of those, not sure why I need an import map in the html file for my three.js module but not for others).

2 Likes

I mean, you just described one of the most canonical reasons to move to typescript :slight_smile:

You can spend hours debugging this, or not, because typescript would tell you that castShadows, doesn’t exist.

I’m surprised that you find this a positive, coming from a strongly typed compiled language. Nowadays I don’t think you need much in terms of configuration, a few dependencies sure, but TS is well worth it.

Just to be clear, I’m responding to this, the way people deal with this is Typescript. Alternatively JSDoc, or perhaps flow.

Yeah definitely I think it’s batty and stupid that javascript allows you to do that stuff in the first place, and I’m sure it’ll continue to drive me crazy. For similar reasons I despise Python. But being able to write a single html file and a single javascript file, without installing a single package and doing anything other than uploading (or running from a terminal-created server), and making pretty cool-looking 3D graphics right away has been neat. I’ll definitely give typescript more consideration.

Won’t that file become big sooner or later? You don’t actually need an html file everything can be generated programmatically.

1 Like

C++ is a strongly typed language.

JavaScript is dynamically typed. It’s compiled at runtime. You can break all kinds of rules and people create magic from it. The language is much more forgiving for this reason, but it does take people far into rabbit holes before they discover that their error was caused by something 100 lines ago.

If you want strong typing, then you can try TypeScript. It absolutely helps with ensuring typos don’t make it to production. But it is a slightly painful concept to understand and get to work for beginners. Article : Do I really need to use TypeScript?

ESLint also helps at writing safer JavaScript, outside the need of TypeScript. It’s kind of somewhere in between.

If you use an IDE like VSCode, you can add the Three type declarations so you can see the correct syntax with some documentation as you develop.

npm install @types/three

This along with JavaScript, won’t stop you from still being able to utilise dynamic typing if you still want to.

The concept of import maps is not that much different than setting your lib paths in a c++ project. You only need import maps if you are importing an addon or third party lib that references “three”. And then you describe where your browser can find “three”. More info and examples of the many ways that you can use import maps.

If you use a build tool like webpack, esbuild, parcel, vite, et.al., then you don’t need import maps.

All the options you find in the JavaScript world will benefit you if you inderstand its purpose and how to correctly use it.

2 Likes

The article is members only, I can’t read it :frowning:

I want to see your take even though I doubt I’ll agree.

What exactly is supposed to happen here? If you don’t want to add a property called castShadows to some random, arbitrary object that doesn’t have it, but instead want to know that you’ve set castShadow on a specific type of object that has this property, you want to see the error. If instead you do want to do this, then won’t the error get in the way? Or does it just help with autocomplete or something like that?

Using types without typescript feels so incredibly hacky, I’m not even sure what’s the point.

Note, this will only work if these packages happen to align. You need to make sure that you install the correct version of the types. I think you need to make sure your IDE picks up the correct version of the types. And finally, the actual types need to be correct. Even though that is the goal there could be an error in some version and you will end up with different JavaScript and different types.

One can always opt out of TS by casting a variable as “any”. One can then slap whatever they want onto an object since it becomes JS at that point.

To be honest, after writing a few more functions I decided to install typescript tonight and I’m going to try developing that way for a few days. :rofl:

1 Like

Thanks for such a well-rounded response, this is very helpful to me!

1 Like

Why stop at JavaScript?

If you’re already using a compiler or transpiler, care deeply about type safety, and find JavaScript’s looseness frustrating, then why not consider a language designed for strong typing from the ground up?

Languages like TypeScript, Rust, C, C++, Dart, Haxe, Scala, Kotlin, and Go offer robust ecosystems, strong types, and dedicated tooling—all of which transpile to JavaScript or WebAssembly (WASM). They deliver the features you’re after without needing to bend JavaScript into something it wasn’t designed to be.

Here’s the thing: if you’re using a bundler/transpiler, you’ve already made a few trade-offs:

  • You’ve accepted a compile step: waiting for changes to build.
  • You’ve reduced raw debuggability: source maps help, but debugging transpiled output is never perfect.
  • You’re relying on non-standard artifacts: introducing tools that can drift from JavaScript’s native ecosystem.

At this point, you’ve essentially moved beyond “plain JavaScript”—and that’s okay! But if you’re committing to all that overhead, why stop at adding types to JavaScript? Why not explore languages explicitly designed for type safety, modern syntax, and better ergonomics?

JavaScript is great when it’s left to be JavaScript. But if you’re crafting a Frankenstein-like “typed JavaScript” anyway, perhaps it’s time to go all in.

p.s.-this comment was transpiled by chatgpt.