About materials
Materials & Textures is a skill for assigning PBR texture maps to Three.js materials. It covers color-space handling and texture tiling, and advises matching assets to surfaces or identifying gaps rather than using a flat color.
Key features
- 01Assign PBR texture maps together
- 02Set map color spaces correctly
- 03Tile textures across large surfaces
- 04Match textures to scene surfaces
Use cases
- 01Texturing terrain and ground
- 02Applying stone to cliffs
- 03Texturing floors and walls
- 04Finding surfaces without fitting assets
Install
Copy the command and run it in a terminal.
npx skills add https:/ / github.com/ drawcall-ai/ skills --skill materialsAfter installing, type/materialsin Claude Code to confirm it loaded.
Details
From the project READMEMaterials & Textures
A MeshStandardMaterial with only a color reads as flat, plastic, "untextured gray" — the fastest tell of an unfinished scene. A finished surface has texture maps. A surface left as a solid color is a fit-gap, not a material.
Apply a texture set
Market texture assets ship a PBR set (base color + normal + roughness/metalness/ao). Load and assign the maps together:
const loader = new TextureLoader()
const base = loader.load('/texture/grass/basecolor.jpg')
base.colorSpace = SRGBColorSpace // base color is sRGB
const normal = loader.load('/texture/grass/normal.jpg') // every other map is linear (leave default)
const rough = loader.load('/texture/grass/roughness.jpg')
const material = new MeshStandardMaterial({ map: base, normalMap: normal, roughnessMap: rough })
Color space — the #1 mistake
- Base-color and emissive maps →
SRGBColorSpace. Forgetting this makes everything look washed-out and grayish. - Normal / roughness / metalness / AO maps stay linear (the default — do not mark them sRGB).
In current Three.js an aoMap shares the primary uv set by default — you do not need to build a second uv2 attribute (that requirement is from older versions).
Tiling for large surfaces
Ground and walls must repeat the texture, not stretch one copy across the whole mesh:
for (const t of [base, normal, rough]) {
t.wrapS = t.wrapT = RepeatWrapping
t.repeat.set(surfaceMeters / tileMeters, surfaceMeters / tileMeters) // ~1 tile per few meters
}
Match each surface to a fitting texture — grass/ground for terrain, stone for cliffs, planks/metal for floors and walls. Pick textures from the asset survey; if none fits a surface, name the gap rather than shipping a flat color.