Wonderland Engine for Unity Developers

This page provides mappings from Unity to Wonderland Engine for scripting and provides a list of differences for building solutions.

Scripting 

Wonderland Engine runs in the Browser, which has a JavaScript runtime already built-in. This makes it the best scripting language choice for a web engine, since nothing additional needs to be downloaded.

To create a script, right-click in the asset browser of Wonderland Editor and create a new JavaScript / TypeScript component. It comes with a basic template to get you started.

A good IDE to use for JS/TS is Visual Studio Code.

For further information on how Wonderland Engine’s API is different from Unity’s, see the Code section.

TypeScript vs JavaScript 

TypeScript adds static type-checking to JavaScript which brings it much closer to C# and greatly improves code completion your IDE. We generally recommend TypeScript to developers familiar with Unity.

Wonderland Engine automatically handles any tsconfig.json setup for you, simply create a TypeScript component from the asset browser.

Packaging 

While a Unity workflow will often use the in-editor preview, in Wonderland Engine the final packaging process so fast (less than 1 second) that the final app in the browser can be used as preview.

The page in the browser will reload whenever you repackage, and check Views > Preferences to make it run automatically after every save.

To deploy the application, you need to simply upload the contents of the deploy folder of your project to a web server. Alternatively, you can upload via the “Wonderland Cloud Publish” plugin which can be activated in Views > Plugins.

Multiple Scenes 

Wonderland Engine allows switching between multiple scenes created in multiple project files (.wlp). Check the Switching Scenes Tutorial for instructions.

You can also stream parts of a scene at runtime, refer to the Streaming .bin Files Tutorial.

Prefabs 

Wonderland Engine does not have an equivalent to prefabs yet. Instead, you can set up a prototype in the scene, and object.clone() the hierarchy with all of its components.

Alternatively, move the prefab object in a separate scene to load it during runtime using engine.loadPrefab(…) and instantiating it.

Importing Assets 

In Wonderland Engine, if a scene file is imported (by drag and drop from the asset browser either into the Scene View or Scene Outline, or by dragging image files into a material’s texture slot), it is linked and watched for changes. The resulting resources that were found in the scene file will be made available in the project and can be viewed in the “Resources” view.

Until a file is imported from the Asset Browser, it is unavailble for use in the project. The “Asset Browser” could be considered a file browser which is different from what you might be used to in Unity.

Optimizing Assets 

Once imported assets can be further optimized:

  • Meshes can be auto-decimated to reduce the vertex count
  • Meshes can be scaled uniformly
  • Images are automatically compressed
  • Images can be downscaled

These settings are found in the “Resources” view.

Directories 

  • deploy contains the final result of packaging.
  • static contains files which are copied to deploy as-is.
  • cache contains cached asset compilation results, e.g. compressed images. Can usually be safely deleted, but will take time to regenerate.

These settings are found in the “Resources” view.

Animations 

Animations are played via the animation component type. Skinned animations are retargeted with the retarget checkbox, if the component is attached to one of the bones/joints of the target skin.

Blending, editing keyframes or keyframe events are not supported yet.

Physics 

Rigid bodies are created via the physx component type. The scene can be simulated in the editor with Debug > Simulate Physics (Alt + S).

Networking 

Peer-to-Peer networking can be achieved with the community supported Wonderland Engine PeerJS Networking.

It uses WebRTC, which to a certain scale can make use of default PeerJS server infrastructure.

Alternatively, the community has integrated Colyseus for multi-user.

UI 

User interface is either set up manually with the cursor, cursor-target, and the collider component.

The follwoing HTML5 Canvas based 2D UI is maintained by the community: Lazy Widgets project.

Terminology 

TermUnityWonderland Engine
ProjectA project file.Possibly multiple project files sharing a single project root directory.
Inspector viewProperties view

Code 

Below is a list of common code patterns and their Wonderland Engine equivalents:

Custom Behaviour 

In Wonderland Engine we have “Component” instead of “MonoBehaviour”. To write one, you simply extend the Component class:

UnityWonderland Engine (JavaScript)Wonderland Engine (TypeScript)
 1using UnityEngine;
 2using System.Collections;
 3
 4public class MainPlayer : MonoBehaviour
 5{
 6  [field: SerializeField]
 7  public string myName;
 8
 9  string privateName;
10
11  void Start()
12  {
13    Debug.Log("My name is", this.myName, this.privateName);
14  }
15
16  void Update()
17  {
18    Debug.Log("Delta time:", Time.deltaTime);
19  }
20}
 1import {Component, Property} from '@wonderlandengine/api';
 2
 3export class MainPlayer extends Component {
 4  static TypeName = 'main-player';
 5
 6  /* Properties are exposed in the editor */
 7  static Properties = {
 8      myName: Property.string("Alice")
 9  };
10
11  privateName = "Bob";
12
13  start() {
14    console.log("My name is", myName, privateName);
15  }
16
17  update(dt) {
18    console.log("Delta time:", dt);
19  }
20}
 1import {Component} from '@wonderlandengine/api';
 2import {property} from '@wonderlandengine/api/decorators.js';
 3
 4export class MainPlayer extends Component {
 5  static TypeName = 'main-player';
 6
 7  /* Properties are exposed in the editor */
 8  @property.string("Alice")
 9  myName!: string;
10
11  privateName = "Bob";
12
13  start() {
14    console.log("My name is", myName, privateName);
15  }
16
17  update(dt: number) {
18    console.log("Delta time:", dt);
19  }
20}

As in Unity, some UI elements will be generated for the parameters.

Get component on game object 

UnityWonderland Engine
1gameObject.GetComponent<MyComponent>();
1// Preferred, since the type can be inferred
2this.object.getComponent(MyComponent);
3
4// or: by type name
5this.object.getComponent('my-component');

Attach a component to an object 

UnityWonderland Engine
1MyComponent sc = gameObject.AddComponent<MyComponent>();
2sc.property = "set";
1this.object.addComponent(MyComponent, {property: "set"});
2
3// or: by type name
4this.object.addComponent('my-component', {property: 'set'});
5
6// or: defer activation
7const sc = this.object.addComponent('my-component', {active: false});
8sc.property = 'set';
9sc.active = true;

Get a child object 

UnityWonderland Engine
1
2gameObject.transform.GetChild(0);
1this.object.children[0];

Get parent object 

UnityWonderland Engine
1gameObject.transform.parent
1this.object.parent;

Set a Material Property 

Set various material properties like color or textures.

UnityWonderland Engine
1var mesh = gameObject.GetComponent<MeshRenderer>();
2mesh.material.SetColor("_Color", Color.green);
1const mesh = this.object.getComponent(MeshComponent);
2mesh.material.diffuseColor = [0.0, 1.0, 0.0, 1.0];

Math 

JavaScript does not support operator overloading, which means that we take a different approach to math code.

In many cases, writing math code can be avoided entirely, since Wonderland Engine’s Object3D API contains many functions to manipulate transformations, efficiently implemented in WebAssembly:

1/* Translate an object on multiple axis. To avoid garbage for the vector, use a temporary vector member or constant in the module scope. */
2this.object.translateWorld([1, 2, 3]);
3
4/* Rotate an object around the Y axis. */
5const AxisY = [0, 1, 0];
6this.object.rotateAxisAngleDegLocal(AxisY, 25);

Garbage Collection 

JavaScript is a garbage collected language which can cause unplanable interruptions due to automatic garbage collection, it is best practice to avoid adding memory onto the heap in form of lists/vectors or objects, which are not trivially collected.

It is best practice to create temporary vectors/quaternions either in the constructor or body of a custom component and be reused, or if used carefully, in the module scope of your component (above the class). Constant vectors like [0, 1, 0] are best declared in the module scope as const AxisY = [0, 1, 0].

Math Library 

We recommend using glMatrix, which is a performance and garbage collection-aware math library for JavaScript/TypeScript. It already comes installed with our default templates and with our default components, so you likely do not need to install it yourself.

Rather than returning a newly allocated vector, glMatrix functions that compute a vector or quaternion will expect the first parameter to be where the result should be written into. Functions that return a primitive will return the result as normal.

Find the full documentation of the glMatrix math library here.

UnityWonderland Engine
1var v = new Vector3(1, 2, 3);
2v.Set(3, 2, 1);
1const v = vec3.fromValues(1, 2, 3);
2vec3.set(v, 3, 2, 1);
1var a = new Vector3(1, 2, 3);
2var b = new Vector3(1, 2, 3);
3
4var v = a + b;
5var a = a * b;
6var a = 2.0*a;
1import {vec3} from 'gl-matrix';
2
3const a = vec3.fromValues(1, 2, 3);
4const b = vec3.fromValues(1, 2, 3);
5
6const v = vec3.add(vec3.create(), a, b);
7vec3.mul(a, a, b);
8vec3.scale(a, a, 2.0);

JavaScript vs C# 

Some more prominent differences when coming from C# include:

  • Always prefix this. to access member variables.
  • var creates a “global”, which is not restricted to the current scope. It is best practice to avoid it and use let or const instead, which create scoped variables.