Download

Common decorators

Retrieve scene objects, components, animation groups, and asset containers directly inside attached scripts.

Introduction

Scripts can retrieve instances from the scene by using common decorators. Those decorators link scene objects directly to properties in your script, making it simple to reference meshes, lights, cameras, or other components without manual searching.

@nodeFromScene

Retrieves any Mesh, TransformNode, Light, or Camera from the scene by its name. The retrieved node is linked directly to the decorated property.

scripts/myScript.ts
import { Mesh } from "@babylonjs/core/Meshes/mesh";

import { nodeFromScene } from "babylonjs-editor-tools";

export default class MyMeshComponent {
    @nodeFromScene("Other Mesh")
    private _otherMesh: Mesh | null = null;

    public constructor(public mesh: Mesh) { }

    public onStart(): void {
        console.log(this.otherMesh);
    }
}

@nodeFromDescendants

Retrieves any Mesh, TransformNode, Light, or Camera from the children of the object the script is attached to.

scripts/myScript.ts
import { Mesh } from "@babylonjs/core/Meshes/mesh";

import { nodeFromDescendants } from "babylonjs-editor-tools";

export default class MyMeshComponent {
    @nodeFromDescendants("Other Mesh")
    private _otherMesh: Mesh | null = null;

    public constructor(public mesh: Mesh) { }

    public onStart(): void {
        console.log(this.otherMesh);
    }
}

@animationGroupFromScene

Retrieves any Animation Group from the scene by name.

scripts/myScript.ts
import { Mesh } from "@babylonjs/core/Meshes/mesh";
import { AnimationGroup } from "@babylonjs/core/Animations/animationGroup";

import { animationGroupFromScene } from "babylonjs-editor-tools";

export default class MyMeshComponent {
    @animationGroupFromScene("Idle")
    private _idle: AnimationGroup | null = null;

    public constructor(public mesh: Mesh) { }

    public onStart(): void {
        this._idle.play();
    }
}

@sceneAsset

Loads and retrieves a scene container. This is useful for reusable assets like maps or enemies that need to be instantiated multiple times on demand.

The retrieved instance is of type AdvancedAssetContainer, which extends the Babylon.js AssetContainer class to support attaching scripts to instantiated entries.

Available methods:

  • removeDefault: When a scene container is loaded, it is automatically instantiated once. Calling this removes those default instances from the scene so you can instantiate them strictly on demand.
  • instantiate: Instantiates the container and returns the root nodes. Learn more in the Babylon.js Documentation (Duplicating the models).
scripts/myScript.ts
import { Mesh } from "@babylonjs/core/Meshes/mesh";

import { sceneAsset, AdvancedAssetContainer } from "babylonjs-editor-tools";

export default class MyMeshComponent {
    @sceneAsset("enemy.scene")
    private _enemy: AdvancedAssetContainer | null = null;

    public constructor(public mesh: Mesh) { }

    public onStart(): void {
        // The container is instantiated by default. You can call .removeDefault() to remove the default instances.
        this._enemy.removeDefault();
        
        // Otherwise, you can keep the default instance and use it in your scene.
        // this._enemy.removeDefault();

        // If the container is used to instantiate multiple entities like enemies, you can call .instantiate().
        for (let i = 0; i < 10; i++) {
            const enemy = this._enemy.instantiate({
                doNotInstantiate: (node) => node.name === "DontInstantiateMe",
                predicate: (entity) => entity.name.startsWith("Enemy"),
            });

            // You can dispose the instantiated entries using .dispose
            enemy.dispose();
        }
    }
}

@componentFromScene

Retrieves the unique reference to a script attached to an object in the scene.

Unique Instances Required
Make sure that only one instance of the target script is attached in the scene. If multiple instances are found, an error is thrown because the editor cannot determine which instance to link.
scripts/myScript.ts
// my-component.ts
import { Mesh } from "@babylonjs/core/Meshes/mesh";

import { nodeFromScene } from "babylonjs-editor-tools";

export default class MyMeshComponent {
    @componentFromScene(MyOtherComponentClass)
    private _myComponennt: MyOtherComponentClass;

    public constructor(public mesh: Mesh) { }

    public onStart(): void {
        this._myComponennt.sayHello();
    }
}

// my-other-component.ts
export default class MyOtherComponentClass {
    ...

    public sayHello(): void {
        console.log("Hello!");
    }
}