How to Use userData in Three.js Object3D

In Three.js, attaching custom metadata to 3D objects is a common requirement for managing game logic, interactivity, and application state. This article provides a quick, direct guide on how to use the built-in userData property of any Object3D to store, update, and retrieve custom user data efficiently.

What is the userData Property?

Every object that inherits from THREE.Object3D (including meshes, lights, cameras, and groups) comes with a built-in, empty object called userData. This property is specifically reserved for developer-defined custom data, ensuring your custom properties do not conflict with the internal properties and methods of Three.js.

Assigning Custom Data

You can assign custom data to userData either by adding individual properties or by defining a new object.

Method 1: Assigning individual properties

const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
const cube = new THREE.Mesh(geometry, material);

// Assign individual properties to userData
cube.userData.id = "cube_99";
cube.userData.type = "interactable";
cube.userData.health = 100;
cube.userData.isCollectible = true;

Method 2: Assigning a complete object

cube.userData = {
    id: "cube_99",
    type: "interactable",
    health: 100,
    isCollectible: true
};

Retrieving Custom Data

To access your custom data later—such as during a raycasting interaction or inside your animation loop—simply reference the userData property of the target object.

// Example: Accessing data during a raycast intersection check
const intersects = raycaster.intersectObjects(scene.children);

if (intersects.length > 0) {
    const hitObject = intersects[0].object;
    
    // Check custom properties stored in userData
    if (hitObject.userData.isCollectible) {
        console.log(`Collected item with ID: ${hitObject.userData.id}`);
        hitObject.userData.health -= 10; // Update the custom state
    }
}

Why Use userData?