ai-behavior-trees-util…
Build a production behavior-tree runtime (Blackboard, action/condition leaves, sequence/selector/parallel composites, decorators)…
Light and shade a three.js scene: choose materials (MeshStandardMaterial PBR vs unlit MeshBasicMaterial), add ambient/hemisphere/directional/point/spot lights, turn on shadow maps, and use an environment map (IBL) for realistic reflections. Use when a three.js model looks black,
Claude Code
$ npx -y skills add gamedev-skills/awesome-gamedev-agent-skills --skill threejs-materials-lighting --agent claude-code
Codex
$ npx skills add gamedev-skills/awesome-gamedev-agent-skills --skill threejs-materials-lighting -a codex -y
Cursor
$ npx skills add gamedev-skills/awesome-gamedev-agent-skills --skill threejs-materials-lighting -a cursor -y
Gemini CLI
$ npx skills add gamedev-skills/awesome-gamedev-agent-skills --skill threejs-materials-lighting -a gemini-cli -y
GitHub Copilot
$ npx skills add gamedev-skills/awesome-gamedev-agent-skills --skill threejs-materials-lighting -a github-copilot -y
OpenCode
$ npx skills add gamedev-skills/awesome-gamedev-agent-skills --skill threejs-materials-lighting -a opencode -y
Windsurf
$ npx skills add gamedev-skills/awesome-gamedev-agent-skills --skill threejs-materials-lighting -a windsurf -y
name: threejs-materials-lighting description: > Lights and shades three.js r187 scenes: standard, physical and unlit materials, lights, shadows, HDR environment lighting and tone mapping. Use when a mesh renders black or washed out, shadows are missing or full of acne, or EffectComposer darkens the image. Not for renderer setup (`threejs-scene-setup`), model loading (`threejs-gltf-loading`) or custom shaders (`shader-programming`).
Makes three.js surfaces read correctly: the right material, a light rig, working shadows and image-based lighting (IBL). Patterns target **r187**. Lighting has been physically based since r155, so intensities from older tutorials look far too dark.
added, or environment reflections (IBL) are being set up.
`renderer.shadowMap.enabled`, `scene.environment` or `renderer.toneMapping`.
(`threejs-gltf-loading`), or custom GLSL and node shaders (`shader-programming` for the technique).
1. **Rule out geometry first.** Swap the material for `MeshNormalMaterial`. If the mesh is still missing, the problem is the camera, scale or loading, not lighting. 2. **Default to `MeshStandardMaterial`.** It reacts to lights and `scene.environment` and matches glTF's PBR model. Use `MeshPhysicalMaterial` only for clearcoat, transmission or sheen, and `MeshBasicMaterial` for unlit UI, sprites and flat colour. 3. **Light the scene**: an environment map or a hemisphere fill, plus one directional key light. Start the key at about 2 to 3. 4. **Turn on shadows in three places**: the renderer, the light, and each mesh's `castShadow` / `receiveShadow`. Then fit the light's shadow camera to the play area. 5. **Tag colour textures sRGB** and leave data maps (normal, roughness, metalness) linear. 6. **Choose a tone mapping curve** once, and finish any post-processing chain with `OutputPass`. 7. **Verify** with [Verify](#verify).
import * as THREE from 'three';
const material = new THREE.MeshStandardMaterial({
color: 0xcc4444,
roughness: 0.5, // 0 = mirror, 1 = matte
metalness: 0.0, // 0 = plastic, wood, skin; 1 = bare metal
});
scene.add(new THREE.Mesh(new THREE.SphereGeometry(1, 32, 16), material));
scene.add(new THREE.HemisphereLight(0xbbddff, 0x443322, 1.0)); // sky, ground, intensity
const key = new THREE.DirectionalLight(0xffffff, 2.5);
key.position.set(5, 10, 7);
scene.add(key);const tex = new THREE.TextureLoader().load('assets/logo.png');
tex.colorSpace = THREE.SRGBColorSpace; // colour maps are sRGB
const logo = new THREE.MeshBasicMaterial({ map: tex, transparent: true }); // ignores lightsrenderer.shadowMap.enabled = true; renderer.shadowMap.type = THREE.PCFShadowMap; // soft since r182 const sun = new THREE.DirectionalLight(0xffffff, 3); sun.position.set(8, 12, 6); sun.castShadow = true; sun.shadow.mapSize.set(2048, 2048); // default 512 const cam = sun.shadow.camera; // orthographic for a DirectionalLight cam.near = 1; cam.far = 40; cam.left = -15; cam.right = 15; cam.top = 15; cam.bottom = -15; scene.add(sun); // scene.add(new THREE.CameraHelper(cam)); // draw the frustum while tuning mesh.castShadow = true; ground.receiveShadow = true;
For a level larger than the shadow frustum, move the light and its `target` with the player each frame instead of growing the frustum, which spreads the same map over more ground. Add the target to the scene (`scene.add(sun.target)`) so its world matrix updates.
const loader = new THREE.TextureLoader();
const colorMap = loader.load('assets/brick_color.jpg');
colorMap.colorSpace = THREE.SRGBColorSpace;
const brick = new THREE.MeshStandardMaterial({
map: colorMap,
normalMap: loader.load('assets/brick_normal.jpg'), // data maps stay linear
roughnessMap: loader.load('assets/brick_rough.jpg'),
metalness: 0,
});import { HDRLoader } from 'three/addons/loaders/HDRLoader.js'; // RGBELoader before r180
new HDRLoader().load('assets/studio.hdr', (hdr) => {
hdr.mapping = THREE.EquirectangularReflectionMapping;
scene.environment = hdr; // lights and reflects every PBR material
scene.background = hdr; // optional backdrop
});
renderer.toneMapping = THREE.ACESFilmicToneMapping; // default is NoToneMapping
renderer.toneMappingExposure = 1.0;No HDR file? The reference shows `RoomEnvironment` through `PMREMGenerator`.
1. `npm run build` (or `npx tsc --noEmit`) passes. 2. Probe the lighting state in the running page. Expose `renderer` and `scene` on `window` (`Object.assign(window, { renderer, scene })`). Then pass this expression to Playwright's `page.evaluate` as a string, so it runs in the page and not in Node (the smoke script in `threejs-scene-setup` works), or ask the user to paste it into the browser console and report the output:
(() => {
const lights = [], casters = [], srgbMissing = [];
window.scene.traverse((o) => {
if (o.isLight) lights.push(`${o.type}:${o.intensity}${o.castShadow ? ':shadow' : ''}`);
if (o.isMesh && o.castShadow) casters.push(o.name || o.type);
for (const m of [].concat(o.material ?? [])) {
if (m.map && m.map.colorSpace !== 'srgb') srgbMissing.push(m.name || m.type);
}
});
return {
lights,
environment: !!window.scene.environment,
shadowMap: window.renderer.shadowMap.enabled,
shadowCasters: casters.length,
toneMapping: window.renderer.toneMapping, // 0 = NoToneMa<img src="docs/assets/awesome-gamedev-agent-skills-banner.png" width="820" alt="awesome-gamedev-agent-skills — game-dev skills for AI coding agents.
Build a production behavior-tree runtime (Blackboard, action/condition leaves, sequence/selector/parallel composites, decorators)…
Implement game audio practice — bus/mixer architecture and gain in decibels, ducking (sidechain), adaptive/dynamic music via…
Build game cameras that feel good — 2D follow with a deadzone, look-ahead, smoothing, and level-bounds clamping; 3D third-person…
Plan, generate, source, normalize, and validate cohesive visual game assets. Use for art direction, style bibles, sprites,…
Build branching dialogue and narrative — a node/choice graph with conditions, variables, and localization hooks — and choose…
Design NPC and enemy decision-making with finite state machines, behavior trees, steering behaviors, and A* pathfinding —…
You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…
Ask which skill or flow fits your situation. A router over the skills in this repo.