Skip to Content
We're building a full JS ecosystem for Unity, with OneJS at the core (open source release soon 🚀). Also cooking up a bunch of pre-made game UIs, plus a big site revamp in progress.

PuerTS  is an open-source integration framework that enables developers to script game logic in JavaScript or TypeScript while seamlessly interfacing with native C++ or C# game engines such as Unreal Engine and Unity.

OneJS use PuerTS for easy access to the 3 JS backends it provides: V8, QuickJS, and NodeJS.

Switching Backends

Having 3 backends to choose from is nice. Use QuickJS for its small build size (~20MB). Use V8 for raw speed and WebAssembly. Use NodeJS for its robust ecosystem.

To check which backend you’re currently using, go to Tools > OneJS > Backend in the Unity menu.

If you want to switch to a different backend, you’ll need to close the Unity Editor first. Then in your terminal or VSCode, run:

npm run switch quickjs

Unity doesn’t have a reliable way to unload and replace native plugins while it’s running, so the editor needs to be closed for the switch to work properly.

PuerTS Primer

Source: chexiongsheng/puerts_unity_demo 

// You can access all C# namespaces and classes from the CS. global namespace in JS const { $ref, $unref, $generic, $promise, $typeof } = puer; // Static function CS.UnityEngine.Debug.Log('hello world'); // Object construction let obj = new CS.PuertsTest.DerivedClass(); // Instance member access obj.BMFunc(); // Parent class method obj.DMFunc(CS.PuertsTest.MyEnum.E1); // Subclass method console.log(obj.BMF, obj.DMF); obj.BMF = 10; // Parent class property obj.DMF = 30; // Subclass property console.log(obj.BMF, obj.DMF); // Static members console.log(CS.PuertsTest.BaseClass.BSF, CS.PuertsTest.DerivedClass.DSF, CS.PuertsTest.DerivedClass.BSF); // Delegates, events // If you don't need -= later, you can pass a function as a delegate directly like this obj.MyCallback = msg => console.log("do not need remove, msg=" + msg); // Delegates created via new can later use this reference for -= let delegate = new CS.PuertsTest.MyCallback(msg => console.log('can be removed, msg=' + msg)); // Since TS doesn't support operator overloading, Delegate.Combine is equivalent to obj.myCallback += delegate in C# obj.MyCallback = CS.System.Delegate.Combine(obj.MyCallback, delegate); obj.Trigger(); // Delegate.Remove is equivalent to obj.myCallback -= delegate in C# obj.MyCallback = CS.System.Delegate.Remove(obj.MyCallback, delegate); obj.Trigger(); // Events obj.add_MyEvent(delegate); obj.Trigger(); obj.remove_MyEvent(delegate); obj.Trigger(); // Static events CS.PuertsTest.DerivedClass.add_MyStaticEvent(delegate); obj.Trigger(); CS.PuertsTest.DerivedClass.remove_MyStaticEvent(delegate); obj.Trigger(); // Variable arguments obj.ParamsFunc(1024, 'haha', 'hehe', 'heihei'); // in out parameters let p1 = $ref(1); let p2 = $ref(10); let ret = obj.InOutArgFunc(100, p1, p2); console.log('ret=' + ret + ', out=' + $unref(p1) + ', ref=' + $unref(p2)); // Generics // First, instantiate generic parameters through $generic let List = $generic(CS.System.Collections.Generic.List$1, CS.System.Int32); //$generic invocation performance isn't great, so it's recommended to use it only once per project or at least per file for the same generic parameter let Dictionary = $generic(CS.System.Collections.Generic.Dictionary$2, CS.System.String, List); let lst = new List(); lst.Add(1); lst.Add(0); lst.Add(2); lst.Add(4); obj.PrintList(lst); let dic = new Dictionary(); dic.Add("aaa", lst); obj.PrintList(dic.get_Item("aaa")); let Arr = CS.System.Array.CreateInstance(puer.$typeof(CS.System.String), 3); Arr.SetValue("aaa", 0); Arr.SetValue("bbb", 1); Arr.SetValue("ccc", 2); obj.PrintArray(Arr); // arraybuffer let ab = obj.GetAb(5); let u8a0 = new Uint8Array(ab); console.log(obj.SumOfAb(u8a0)); let u8a1 = new Uint8Array(2); u8a1[0] = 123; u8a1[1] = 101; console.log(obj.SumOfAb(u8a1)); // Engine API let go = new CS.UnityEngine.GameObject("testObject"); go.AddComponent($typeof(CS.UnityEngine.ParticleSystem)); go.transform.position = new CS.UnityEngine.Vector3(7, 8, 9); // Extension methods puer.$extension(CS.PuertsTest.BaseClass, CS.PuertsTest.BaseClassExtension); obj.PlainExtension(); obj.Extension1(); obj.Extension2(go); let obj1 = new CS.PuertsTest.BaseClass1(); obj.Extension2(obj1);