Getting Started

Below is a quick tutorial to get started with Custom JavaScript scripting.

Before continuing make sure that you install the SDK.

Create a JavaScript File

To start, let's create a JavaScript file that we will use to code.

  1. Right click somewhere in your project folder.

  2. Select Create > Javascript File.

  1. Name your Javascript file as you wish.

Writing a Script

The Metaverse Scripting engine provides some basic interop that is familiar to those who have experience with Unity C# components. See the example below:

const UnityEngine = importNamespace('UnityEngine');

let rigidbody = gameObject.GetComponent(UnityEngine.Rigidbody);

/** Called when the meta space has initialized. */
function Start() {
    UnityEngine.Debug.Log("Hello world!");

/** Called every frame. */
function Update() {
    const yOffset = UnityEngine.Mathf.Sin(UnityEngine.Time.time);
    transform.position = new UnityEngine.Vector3(0, yOffset, 0);

/** Called every physics frame. */
function FixedUpdate() {
    const force = UnityEngine.Vector3.up * UnityEngine.Time.deltaTime;
    rigidbody.AddForce(force, UnityEngine.ForceMode.Acceleration);
    UnityEngine.Debug.Log("I can also run in fixed update!");

As you can see, much (if not most) of what you can do in Unity can be done in JavaScript.

Slight Caveats

Since the JavaScript is being translated into C#, some things may have to be done with odd conventions.

JavaScript Object and Array Initialization

Objects and arrays cannot be initialized with variables, instead they must be initialized, and then the variables assigned afterward, like so:

const myObject = {};
myObj.myVar = "some value";

const myArray = [];

Failure to do this will result in missing variable declarations and/or array elements.

Method Overloads & Default Parameters

When calling a C# method from JavaScript, it's important to understand that the system does not automatically resolve overloads. Consequently, it's uncertain which version of an overloaded method will be called. Moreover, methods won't automatically resolve parameters that have default values. To effectively call C# methods from JavaScript, one must consider these limitations and possibly use more explicit methods or handle parameters in a way that ensures the correct method overload is used and default parameters are appropriately managed.


To use namespaces, declare them with const MyNamespace = importNamespace('myCSharpNamespace');. References to types within this namespace must explicitly use MyNamespace.MyClass since namespaces are not automatically referenced.


One should strongly consider the performance implications of using JavaScript for custom scripting (as opposed to Visual Scripting and PlayMaker) since it can cause potentially large GC allocations.

If you do utilize JavaScript, use a system/manager/service design pattern, rather than individual components per object.

If you'd like more information on how translation from C# to JavaScript might work, consult the Jint documentation.

For information on what functions are not allowed, click here.

Attaching a Script to a Game Object

To allow your script to run on a specific Game Object, you'll want to follow these instructions.

  1. Add the Metaverse Script component to your game object of choice.

  2. Once added, assign the JavaScript file to the JavaScript File field in the inspector.

You've successfully created your first custom script! Now you can hit the Play button and test it out! 🎉

Using Multithreading and Tasks

You can perform wait operations using System.Threading.Tasks. Since the Javascript interop functions differently within this environment (not the normal Javascript then(() => {}) or await flow), you have to utilize a custom await syntax built into the Reach framework. Here's an example below:

const task = SomeCSharpOperationAsync();
await(task, result => { // You don't have to specify the "result" parameter. It's for retreiving the tasks result.
    // Then you can perform your operation here. 
    // UniTask will automatically return to the main Unity thread since that's where
    // this was triggered originally.

Last updated