Skip to content

Object3D Reference

Wraps the live THREE.Object3D for an entity. Almost every entity that renders to the scene carries an Object3DRef so transform sync, selection, and parenting systems can manipulate the underlying object. The object reference may be replaced when assets finish loading. Read it fresh inside system/script hooks rather than caching it across frames.

Managed by: ObjectManagementSystem (hierarchy), ObjectVisibilitySystem (visibility)

Properties

PropertyTypeDescription
objectTHREE.Object3DLive three.js object placed in the scene graph. May be replaced when assets finish loading.
visibilitybooleanWhether the object is currently visible. Mirrors object.visible and is preserved across reloads.

API reference

Scripting examples

Component access patterns

Use this.getComponent(X) to access a component on the entity this script is attached to. Use this.world.getEntityByName to find another entity by name, then this.world.getComponent to read its component:

typescript
// Component on the entity this script is on
const ref = this.getComponent(Object3DRef);

// Component on another entity, found by its scene name
const other = this.world.getEntityByName("Obstacle");
if (other) {
  const ref = this.world.getComponent(other.entityId, Object3DRef);
}

Toggle visibility from the inspector

Expose a boolean that shows or hides the entity's scene object at runtime.

typescript
import { Behaviour, Object3DRef } from "@relu-interactives/spatial-ecs";
import type { BooleanInput } from "@relu-interactives/spatial-ecs";

export default class VisibilityDriver extends Behaviour {
  data = {
    visible: true as BooleanInput,
  };

  protected onUpdate() {
    const ref = this.getComponent(Object3DRef);
    if (ref) ref.visibility = this.data.visible;
  }
}

Flash the object on and off

Alternate visibility every half-second, useful for damage flashes or blinking pickups.

typescript
import { Behaviour, Object3DRef } from "@relu-interactives/spatial-ecs";
import type { FloatInput } from "@relu-interactives/spatial-ecs";

export default class ObjectFlash extends Behaviour {
  data = {
    flashRate: 2 as FloatInput, // flashes per second
  };

  private elapsed = 0;

  protected onUpdate() {
    this.elapsed += this.deltaTime;
    const ref = this.getComponent(Object3DRef);
    if (!ref) return;

    // Alternate visibility based on sine wave sign
    ref.visibility = Math.sin(this.elapsed * this.data.flashRate * Math.PI) >= 0;
  }
}

Via EntityInput in the inspector

Alternatively, pick an entity from the inspector using an EntityInput field and then read the component off that entity via world.getComponent:

typescript
import {
  Behaviour,
  Object3DRef,
  type EntityInput,
  type WorldEntityView,
} from "@relu-interactives/spatial-ecs";

export default class Example extends Behaviour {
  data = {
    targetEntity: { type: "entity", value: null } as unknown as EntityInput,
  };

  protected onUpdate() {
    const entity = this.data.targetEntity.value as WorldEntityView | null;
    if (!entity) return;

    const ref = this.world.getComponent(
      entity.entityId,
      Object3DRef,
    ) as Object3DRef | null;
    if (!ref) return;
    // Use the component on the picked entity.
  }
}

Do not cache the object reference

The underlying object on Object3DRef may be replaced when assets finish loading. Always read ref.object fresh inside system/script hooks rather than caching it in a class field.