LeCodesdocs

Material

What a 3D surface looks like. The built-in looks are static factories — Material.lit (PBR), Material.unlit (flat), Material.video, Material.shadow — and custom compiled shaders load as materials too. Uniforms are set through .set() / the uniforms proxy, which lowers each JS value to the right native uniform call. Assign to a mesh via mesh.material — see Mesh.

At a glance

TypeScript
const tex = await Texture.load(asset('./crate.jpg'))
const crate = Mesh.box({ material: Material.lit({ color: '#ffffff', map: tex }) })
const marker = Mesh.sphere({ material: Material.unlit({ color: '#0f0' }) })
scene.add(crate, marker)

crate.material.set('roughness', 0.3).set('metallic', 1)

Factories

TypeScript
Material.lit(options?: { color?: ColorInput, map?: Texture | Canvas | null,
                         roughness?: number, metallic?: number }): Material   // PBR lit
Material.unlit(options?: { color?: ColorInput, map?: Texture | Canvas | null }): Material  // flat, ignores lights
Material.video(map?: Texture): Material              // samples a VideoPlayer texture
Material.shadow(color = '#000000aa'): Material       // shadow-catcher: invisible except where shadows fall
Material.load(url: string): Promise<Material>        // custom compiled shader (.mat / filamat)
  • lit needs light to be visible — IBL and/or a Light.sun(). Its PBR scalars are 0–1: roughness 0 = mirror, 1 = matte; metallic 0 = dielectric, 1 = metal (both are plain uniforms — unset means the shader's default, and .set('roughness', v) changes them later).
  • video takes the texture from VideoPlayer.texture.
  • shadow is the AR staple: a ground plane that shows only the shadows cast on it.

Color & map

TypeScript
material.color = '#ff8800'            // any ColorInput
material.map = tex                    // Texture, or a Canvas (baked to a texture on assign)
material.map = null                   // remove the map

color and map are conveniences over the underlying uniforms (baseColor / baseColorMap on lit/unlit, color on shadow). On a custom material they don't know the uniform names — color is a silent no-op and map writes baseColorMap; set your own uniforms directly instead.

Custom shaders & uniforms

TypeScript
const material = await Material.load(asset('./hologram.mat'))
// or, from a response you already have:
const material = new Material(await fetch(asset('./hologram.mat'), { useOnce: true }))

material.set(key: string, value): this      // chainable
material.uniforms[key] = value              // same thing, property-style
material.uniforms.speed                     // reads return the last value YOU set (no native read)

Each value type lowers to a specific uniform call:

JS value Lowered to
'#rrggbb' string RGB color
'#rrggbbaa' string RGBA color
number float
boolean bool
Texture sampler (honors the texture's wrapS/wrapT)
number[] / Float32Array float array / vector
null clears the uniform
Note

color strings must be #-hex here — the wider ColorInput forms (rgba(…), packed ints) are only understood by the color setter, not by set(). And a Vec3/Quat wrapper is not lowered — spread it to a plain array first: material.set('dir', [...v]).

The scene occlusion material

scene.occlusionMaterial hands back the scene's occlusion material as a regular Material, so you can set uniforms on it — see Scene (host-gated: not available on the web viewer).

Pitfalls

TypeScript
// ✗ expecting material.color to work on a custom shader
customMat.color = '#f00'                  // no-op: the SDK doesn't know your uniform's name
// ✓ address the uniform directly
customMat.set('baseColor', '#ff0000')

// ✗ passing a Vec3 as a uniform value
mat.set('lightDir', dir)                  // not an Array — lowers to NULL, not a vec3
// ✓
mat.set('lightDir', [...dir])

See also

  • Mesh — assigning materials (mesh.material, setMaterial(index))
  • Texture — loading maps, wrap modes, video textures
  • Light — what lit materials respond to
  • SceneocclusionMaterial, setMaterialGlobalParameter for custom shaders