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
| Property | Type | Description |
|---|---|---|
value | EntityId | null | Parent entity id, or null for root-level entities. |
API reference
- Class:
ParentId - Source:
core/components/ParentId.ts
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:
// 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.
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.
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:
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.
}
}Navigate the hierarchy with World methods
Instead of querying the ParentId component directly, use world.getEntitiesParent and world.getEntitiesChildren for convenient hierarchy traversal:
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.

