# Why isn't MeshBasicMaterial the base class for MeshLambertMaterial?

**URL:** <https://discourse.threejs.org/t/why-isnt-meshbasicmaterial-the-base-class-for-meshlambertmaterial/88948>\
**Category:** Questions\
**Tags:** class, phong-material, lambert-material, basic-material, threejs\
**Created:** [January 4, 2026, 5:19pm UTC](https://discourse.threejs.org/t/why-isnt-meshbasicmaterial-the-base-class-for-meshlambertmaterial/88948 "2026-01-04T17:19:26Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![torrent](https://avatars.discourse-cdn.com/v4/letter/t/4bbf92/32.png) [@torrent](https://discourse.threejs.org/u/torrent)\
**Post date:** [January 4, 2026, 5:19pm UTC](https://discourse.threejs.org/t/why-isnt-meshbasicmaterial-the-base-class-for-meshlambertmaterial/88948/1 "2026-01-04T17:19:26Z")

</div>

I was wondering why in three.js, `MeshLambertMaterial` isn’t a subclass of `MeshBasicMaterial`, if lambert is just the basic material plus simple lighting.

Same thing for phong – `MeshPhongMaterial` is just a lambert material with phong reflections.

So technically, `MeshBasicMaterial` should be the base class for `MeshLambertMaterial`, and `MeshLambertMaterial` should be the base class for `MeshPhongMaterial`, am I right? Right now, it is not so in the three.js code – all three of those material classes are “independent” from one another.

Right now those three material classes look like this in three.js:

```javascript
class MeshBasicMaterial extends Material { }
class MeshLambertMaterial extends Material { }
class MeshPhongMaterial extends Material { }

```

But, shouldn’t it look like this?

```javascript
class MeshBasicMaterial extends Material { }
class MeshLambertMaterial extends MeshBasicMaterial { }
class MeshPhongMaterial extends MeshLambertMaterial { }

```

This is a problem when you are trying do “proper” type checking when working with materials. For example, if you are writing a function that needs to set the `color` property of a material, you have to know ahead of time of all of the materials that could possibly support a `color` property, like this:

```javascript
function setColor(material) {
    if((material instanceof MeshBasicMaterial) || (material instanceof MeshLambertMaterial) || (material instanceof MeshPhongMaterial)) {
        material.color = new Color(1, 0, 0);
        return;
    }
    throw new Error(`material type ${material} not supported`);
}

```

On the other hand, if those three material types were in a prototype chain, where `MeshBasicMaterial` were the highest-level material type that supports a `color` property, you could simplify your code to this:

```javascript
function setColor(material) {
    if(material instanceof MeshBasicMaterial) {
        // we still make it here if the material is MeshLambertMaterial or MeshPhongMaterial
        material.color = new Color(1, 0, 0);
        return;
    }
    throw new Error(`material type ${material} not supported`);
}

```

---

<div class="post-metadata">

**Author:** ![PavelBoytchev](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/pavelboytchev/32/38639_2.png) [@PavelBoytchev](https://discourse.threejs.org/u/PavelBoytchev)\
**Post date:** [January 4, 2026, 5:51pm UTC](https://discourse.threejs.org/t/why-isnt-meshbasicmaterial-the-base-class-for-meshlambertmaterial/88948/2 "2026-01-04T17:51:38Z")

</div>

```javascript
function setColor(material) {
    if(material.color) {
        material.color = new Color(1, 0, 0);
        return;
    }
    throw new Error(`material type ${material} not supported`);
}

```

---

<div class="post-metadata">

**Author:** ![torrent](https://avatars.discourse-cdn.com/v4/letter/t/4bbf92/32.png) [@torrent](https://discourse.threejs.org/u/torrent)\
**Post date:** [January 4, 2026, 5:54pm UTC](https://discourse.threejs.org/t/why-isnt-meshbasicmaterial-the-base-class-for-meshlambertmaterial/88948/3 "2026-01-04T17:54:47Z")

</div>

I knew someone here would post that exact workaround, but simply checking for the existence of a property is not type checking, and would not be acceptable in a professional library.

---

<div class="post-metadata">

**Author:** ![PavelBoytchev](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/pavelboytchev/32/38639_2.png) [@PavelBoytchev](https://discourse.threejs.org/u/PavelBoytchev)\
**Post date:** [January 4, 2026, 6:03pm UTC](https://discourse.threejs.org/t/why-isnt-meshbasicmaterial-the-base-class-for-meshlambertmaterial/88948/4 "2026-01-04T18:03:28Z")

</div>

> [@torrent](#):
>
> This is a problem when you are trying do “proper” type checking when working with materials.

You framed “proper” in quotes. I interpreted this as _pseudo proper_.

BTW even if you do what you propose, what about `MeshStandardMaterial`? You still have to explicitly check for it.

---

<div class="post-metadata">

**Author:** ![manthrax](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/manthrax/32/2596_2.png) [@manthrax](https://discourse.threejs.org/u/manthrax)\
**Post date:** [January 4, 2026, 7:19pm UTC](https://discourse.threejs.org/t/why-isnt-meshbasicmaterial-the-base-class-for-meshlambertmaterial/88948/5 "2026-01-04T19:19:02Z")

</div>

In a high-performance 3D engine, ‘professional’ design patterns often look different than they do in standard enterprise JS. Three.js has evolved over a decade with a clear priority: **Performance \> Minimal Bloat \> Maintainability.** \> While both materials share shader chunks and inherit from the base `Material` class, their shading models are fundamentally different.

Forcing an inheritance relationship between them would create ‘code smells’ where the child class is forced to override or ignore almost everything the parent does.

If you prefer a more traditional logical abstraction, libraries like R3F provide that layer, but the core engine stays flat and low-level for the sake of the GPU.

---

<div class="post-metadata">

**Author:** ![dubois](https://avatars.discourse-cdn.com/v4/letter/d/e9c0ed/32.png) [@dubois](https://discourse.threejs.org/u/dubois)\
**Post date:** [January 5, 2026, 9:28am UTC](https://discourse.threejs.org/t/why-isnt-meshbasicmaterial-the-base-class-for-meshlambertmaterial/88948/6 "2026-01-05T09:28:42Z")

</div>

Like everything in graphics… it’s complicated.

The real question is why not a `ShaderMaterial`

You wouldn’t really get much by extending Phong from Lambert in JavaScript. They are all just some flags (like is it transparent) and some uniforms (like a color or texture).

The flags are mostly not shader related, they tell the renderer what to do with WebGL before running the shader. Thus makes sense that they live on the super class. Some materials won’t have color, so i think you’d quickly run into the diamond problem.

So this is mostly a convention, that the particular material instance will have some conveniently named properties, some other won’t. Also legacy, there are many internal checks in the renderer, that do specific stuff based on the type of material.

At the end of the day all of the materials get broken down into the vertex/fragment shader pair and uniforms. Which is no more and no less than what the `ShaderMaterial` is.

Except, the actual shaders, the strings themselves do not exist on something like MeshBasicMaterial, it’s very indirect (shader chunks) and the renderer ends up making a ShaderMaterial essentially but which you can’t see.

So there is a “template” which is written in augmented GLSL, each material has one. Inheritance doesn’t work here, composition does, so many of these templates overlap. Yes, lambert and phong will have everything that basic does. Phong may not have everything that lambert does because if I’m not mistaken, historically lambert has been done in the vertex shader in three. The common ancestor would be some “material with normals”.
