Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
openaec-foundation avatar

Threejs Core Scene Graph

  • 21 installs
  • 11 repo stars
  • Updated July 8, 2026
  • openaec-foundation/three.js-claude-skill-package

Helps with ai & agent building tasks.

About

threejs-core-scene-graph is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted development.

  • threejs-core-scene-graph
  • AI & Agent Building
  • AI-coding skill

Threejs Core Scene Graph by the numbers

  • 21 all-time installs (skills.sh)
  • +2 installs in the week ending Aug 4, 2026 (Skillselion tracking)
  • Ranked #10,307 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
  • Data as of Aug 4, 2026 (Skillselion catalog sync)
npx skills add https://github.com/openaec-foundation/three.js-claude-skill-package --skill threejs-core-scene-graph

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs21
repo stars11
Last updatedJuly 8, 2026
Repositoryopenaec-foundation/three.js-claude-skill-package

What it does

Helps with ai & agent building tasks.

Files

SKILL.mdMarkdownGitHub ↗

threejs-core-scene-graph

Quick Reference

Scene Graph Hierarchy

ClassExtendsPurpose
Object3DEventDispatcherBase class for ALL 3D objects. Provides transform, hierarchy, traversal
SceneObject3DRoot container. Adds background, environment, fog, overrideMaterial
GroupObject3DSemantic container with no extra functionality. Use for logical grouping
MeshObject3DGeometry + Material. The primary visible object in a scene
CameraObject3DView projection. ALWAYS add to scene for matrix updates
LightObject3DIllumination. ALWAYS add to scene for rendering

Object3D Core Properties

PropertyTypeDefaultDescription
positionVector3(0,0,0)Local position relative to parent
rotationEuler(0,0,0,'XYZ')Local rotation. Linked to quaternion -- modifying one ALWAYS updates the other
quaternionQuaternion(0,0,0,1)Local rotation as quaternion. Linked to rotation
scaleVector3(1,1,1)Local scale. Non-uniform scale causes normal distortion
visiblebooleantrueWhen false, object and ALL descendants are skipped during rendering
layersLayerslayer 032-bit bitmask for selective rendering and raycasting
castShadowbooleanfalseWhether object casts shadows
receiveShadowbooleanfalseWhether object receives shadows
frustumCulledbooleantrueSet false for skyboxes or objects that MUST always render
renderOrdernumber0Higher values render later. Use for transparency sorting
namestring""Human-readable label. Use getObjectByName() for lookup
userDataobject{}Custom application data dictionary

Identity Properties

PropertyTypeDescription
uuidstringRead-only RFC 4122 v4 identifier. Auto-generated
idnumberAuto-incrementing integer. Unique per runtime session
namestringUser-assigned. NEVER relied upon as unique identifier
typestringRead-only class name (e.g., "Mesh", "Group")

Critical Warnings

NEVER modify children array directly -- ALWAYS use add(), remove(), clear(), or attach(). Direct modification breaks internal bookkeeping (parent references, event dispatch).

NEVER modify the children array during traverse() -- collect objects first, then modify after traversal completes. Adding during traversal causes unpredictable iteration.

NEVER use add() when reparenting an object that must keep its world position -- ALWAYS use attach() instead. add() preserves local transform; attach() preserves world transform.

NEVER read matrixWorld after changing position/rotation/scale in the same frame without calling updateWorldMatrix(true, false) first -- the world matrix is stale until the next render or explicit update.

NEVER store Three.js objects in userData without manual disposal -- userData is NOT automatically cleaned up by dispose().

NEVER forget to dispose textures, geometries, and materials when removing objects -- remove() and clear() only detach from the scene graph, they do NOT free GPU memory.

---

Hierarchy Methods

add() vs attach() -- The Critical Difference

import { Scene, Group, Mesh, BoxGeometry, MeshStandardMaterial } from 'three';

const scene = new Scene();
const groupA = new Group();
const groupB = new Group();
groupA.position.set(10, 0, 0);
groupB.position.set(0, 5, 0);
scene.add(groupA, groupB);

const mesh = new Mesh(new BoxGeometry(), new MeshStandardMaterial());
mesh.position.set(0, 0, 0);
groupA.add(mesh);
// mesh world position = (10, 0, 0) -- inherited from groupA

// WRONG: add() preserves LOCAL transform -- mesh jumps to (0, 5, 0) world
groupB.add(mesh); // auto-removes from groupA first

// CORRECT: attach() preserves WORLD transform -- mesh stays at (10, 0, 0) visually
groupA.add(mesh); // reset
groupB.attach(mesh); // mesh.position is recalculated to maintain world position

remove(), removeFromParent(), clear()

// Remove specific children
group.remove(meshA, meshB);

// Remove self from parent (safe when parent is null)
mesh.removeFromParent();

// Remove ALL children -- ALWAYS prefer over manual iteration
group.clear();

Edge case: remove() NEVER throws if the object is not a child -- it silently does nothing.

---

Traversal

// Depth-first traversal of ALL descendants
scene.traverse((object) => {
  if (object.isMesh) {
    object.castShadow = true;
  }
});

// Skip invisible objects and their subtrees
scene.traverseVisible((object) => {
  // only visits objects where visible === true
});

// Walk UP to root (does NOT include the starting object)
mesh.traverseAncestors((ancestor) => {
  console.log(ancestor.name);
});

// Find by name, id, or arbitrary property
const wall = scene.getObjectByName('north-wall');
const obj = scene.getObjectById(42);
const selectable = scene.getObjectByProperty('userData', { selectable: true });

Performance: All search methods are O(n). For frequent lookups, ALWAYS cache the reference.

---

Matrix System

Automatic Mode (Default)

The renderer calls updateMatrixWorld() on the scene before every render, which recursively: 1. Calls updateMatrix() on each object (composes matrix from position/rotation/scale) 2. Computes matrixWorld = parent.matrixWorld * matrix

Manual Mode (Performance Optimization)

// For static objects -- skip per-frame matrix recomputation
object.matrixAutoUpdate = false;
object.matrix.compose(position, quaternion, scale);
object.matrixWorldNeedsUpdate = true;

Reading World-Space Values Mid-Frame

import { Vector3, Quaternion } from 'three';

object.position.set(10, 0, 0);
object.updateWorldMatrix(true, false); // update parents first

const worldPos = new Vector3();
object.getWorldPosition(worldPos);

const worldQuat = new Quaternion();
object.getWorldQuaternion(worldQuat);

const worldScale = new Vector3();
object.getWorldScale(worldScale);

const worldDir = new Vector3();
object.getWorldDirection(worldDir);

Coordinate Conversion

// MUTATION WARNING: both methods modify the input vector in-place
const localPoint = new Vector3(5, 0, 0);
object.localToWorld(localPoint); // localPoint is now in world coordinates

const worldPoint = new Vector3(15, 3, 0);
object.worldToLocal(worldPoint); // worldPoint is now in object's local coordinates

---

Scene Class

import { Scene, Color, Fog, FogExp2, TextureLoader } from 'three';

const scene = new Scene();
scene.background = new Color(0x222222);         // solid color
scene.environment = hdrTexture;                  // IBL for all PBR materials
scene.environmentIntensity = 1.5;                // boost environment lighting
scene.environmentRotation.set(0, Math.PI, 0);   // rotate environment
scene.fog = new Fog(0xcccccc, 10, 100);         // linear fog
scene.overrideMaterial = depthMaterial;          // debug: force all objects to one material
PropertyTypeDefaultDescription
background`Color \Texture \CubeTexture \
environment`Texture \null`null
fog`Fog \FogExp2 \null`
overrideMaterial`Material \null`null
backgroundBlurrinessnumber0Blur for background (0-1)
backgroundIntensitynumber1Background brightness multiplier
backgroundRotationEuler(0,0,0)Background rotation
environmentIntensitynumber1Environment map brightness multiplier
environmentRotationEuler(0,0,0)Environment map rotation

---

Fog

Fog (Linear Interpolation)

import { Fog } from 'three';
scene.fog = new Fog(0xffffff, 10, 200); // color, near, far

FogExp2 (Exponential Density)

import { FogExp2 } from 'three';
scene.fog = new FogExp2(0xffffff, 0.01); // color, density

Material interaction: Every material has a fog property (default: true). ShaderMaterial and RawShaderMaterial default to fog: false -- you MUST set fog: true and include fog shader chunks manually for custom shaders to respond to fog.

---

Group

Group extends Object3D with zero additional functionality. It exists purely as a semantic container for organizing objects:

import { Group } from 'three';

const buildingGroup = new Group();
buildingGroup.name = 'building-01';
buildingGroup.add(walls, roof, foundation);
scene.add(buildingGroup);

// Transform all children together
buildingGroup.position.set(50, 0, 0);
buildingGroup.rotation.y = Math.PI / 4;

---

Mesh

Mesh combines a BufferGeometry with a Material to create a visible surface:

import { Mesh, BoxGeometry, MeshStandardMaterial } from 'three';

const mesh = new Mesh(
  new BoxGeometry(1, 1, 1),
  new MeshStandardMaterial({ color: 0x00ff00 })
);

// Multi-material with geometry groups
const materials = [materialA, materialB];
geometry.addGroup(0, 36, 0);   // start, count, materialIndex
geometry.addGroup(36, 36, 1);
const multiMesh = new Mesh(geometry, materials);

// Morph targets
mesh.morphTargetInfluences[0] = 0.5; // blend between base and morph target

---

Layers System

A 32-bit bitmask system for selective rendering and raycasting:

import { Layers } from 'three';

// Objects are on layer 0 by default
mesh.layers.set(1);        // ONLY layer 1 (removes from layer 0)
mesh.layers.enable(2);     // add layer 2 (keep layer 1)
mesh.layers.disable(1);    // remove layer 1
mesh.layers.toggle(3);     // flip layer 3

// Camera renders only objects with overlapping layers
camera.layers.enable(1);   // camera now sees layers 0 AND 1

// Test overlap
const visible = camera.layers.test(mesh.layers); // true if any layer overlaps

Use cases:

  • Layer 0: default visible objects
  • Layer 1: helpers/gizmos (disable on production camera)
  • Layer 2: bloom-only objects (selective post-processing)
  • Layers 3-31: custom (collision groups, selection sets, LOD groups)

---

lookAt() Behavior Difference

// Camera: points NEGATIVE-Z toward target (looks AT the target)
camera.position.set(0, 5, 10);
camera.lookAt(0, 0, 0);

// Non-camera objects: points POSITIVE-Z toward target
mesh.lookAt(targetPosition);

ALWAYS call lookAt() after setting position -- it computes rotation from the current position.

---

Reference Links

  • references/methods.md -- Complete Object3D, Scene, Group, Mesh, Layers API signatures
  • references/examples.md -- Working code examples for common scene graph operations
  • references/anti-patterns.md -- What NOT to do with scene graph management

Official Sources

  • https://threejs.org/docs/#api/en/core/Object3D
  • https://threejs.org/docs/#api/en/scenes/Scene
  • https://threejs.org/docs/#api/en/scenes/Fog
  • https://threejs.org/docs/#api/en/scenes/FogExp2
  • https://threejs.org/docs/#api/en/objects/Group
  • https://threejs.org/docs/#api/en/objects/Mesh
  • https://threejs.org/docs/#api/en/core/Layers

Related skills

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.