Skip to content

Parent ​

Records the parent entity id for hierarchical scene graphs. null means the entity is at the world root. The ObjectManagementSystem reconciles scene-graph parenting from this component each frame.

Properties ​

PropertyTypeDescription
valueEntityId | nullParent entity id, or null for root-level entities.

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 parentId = this.getComponent(ParentId);

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

Detach an entity to the world root on key press ​

Set ParentId.value to null to reparent the entity to the scene root. The ObjectManagementSystem reconciles the actual scene-graph hierarchy every frame.

typescript
import { Behaviour, KeyboardKeys } from "@relu-interactives/spatial-ecs";
import { ParentId } from "@relu-interactives/spatial-ecs/components";

export default class DetachOnKey extends Behaviour {
  protected onUpdate() {
    if (this.world.getKeyDown(KeyboardKeys.D)) {
      const parent = this.getComponent(ParentId);
      if (parent) parent.value = null;
    }
  }
}

Reparent to a specific entity ​

Assign a new parent entity ID to move the entity (and its children) under a different part of the hierarchy at runtime.

typescript
import { Behaviour, KeyboardKeys } from "@relu-interactives/spatial-ecs";
import { ParentId, Name } from "@relu-interactives/spatial-ecs/components";
import type { TextInput } from "@relu-interactives/spatial-ecs";

export default class Reparenter extends Behaviour {
  data = {
    newParentName: "Holder" as TextInput,
  };

  protected onUpdate() {
    if (!this.world.getKeyDown(KeyboardKeys.R)) return;

 // Find the target parent entity by name
    const parentEntity = this.world.getEntityByName(this.data.newParentName);
    if (!parentEntity) return;

    const parent = this.getComponent(ParentId);
    if (parent) parent.value = parentEntity.entityId;
  }
}

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,
  type EntityInput,
  type WorldEntityView,
} from "@relu-interactives/spatial-ecs";
import {
  ParentId,
} from "@relu-interactives/spatial-ecs/components";

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 parentId = this.world.getComponent(
      entity.entityId,
      ParentId,
    ) as ParentId | null;
    if (!parentId) return;
    // Use the component on the picked entity.
  }
}

Instead of querying the ParentId component directly, use world.getEntitiesParent and world.getEntitiesChildren for convenient hierarchy traversal:

typescript
import { Behaviour } from "@relu-interactives/spatial-ecs";

export default class HierarchyLogger extends Behaviour {
  protected init() {
    // Get parent entity
    const parent = this.world.getEntitiesParent(this.entityId);
    if (parent) {
      console.log(`Parent: ${parent.name} (ID: ${parent.entityId})`);
    }

    // Get all children
    const children = this.world.getEntitiesChildren(this.entityId);
    console.log(`${children.length} child(ren):`);
    for (const child of children) {
      console.log(`  - ${child.name} (ID: ${child.entityId})`);
    }
  }
}

ObjectManagementSystem

Do not call THREE.Object3D.add / remove directly to reparent. Write to ParentId.value instead — the ObjectManagementSystem reads this every frame and reconciles the scene graph. This keeps the ECS hierarchy state consistent with the three.js scene graph.