babyLua - Lua implementation for BabylonJS

Welcome to babyLua, a full Lua VM inside BabylonJS!

This project is still WIP, it’s not public yet!
Ever wanted to write a browser game (or any project at all) using BabylonJS, but you found out TypeScript just isn’t the optimal language? Well, Lua could be it!

babyLua implements a Lua VM with translation layer (wasmoon) inside your project and maps it as a new module, with optimal user friendliness. All you have to do is write a new script like below and enjoy the ride!

import { LuaExecute } from "lua";

async function main(): Promise<void> {
    console.log(await LuaExecute("print('Hello world!') return true"));
//  >>> true (JS boolean)
}

main();

Currently your main script still has to be TS, so you can only mod in Lua, but that will change soon. The editor already has a plugin that can automatically install and map this entire package for you, but no method to run only Lua yet.

Early Beta showcase:

As far as I know the Lua layer can currently do everything vanilla JS can too regarding syntax, but I may be wrong on that.

Any feedback is always appreciated!

FAQ:
Q: Can this run in the browser too?
A: Yes! It requires WebAssembly, so any program that can run BabylonJS can run this too.
Q: Do I have to install this using the Editor plugin?
A: No, you can also manually install it from Github (coming soon), but the plugin makes life easier for you.
Q: Can hackers inject in my Lua code?
A: Yes, but they can hack in your TypeScript code as well so there’s no difference in that. If you export your Lua code as bytecode it’s less readable than regular TS/JS though.
Q: Is Lua faster than JavaScript?
A: It really depends on your setup, but usually JavaScript is a bit faster. babyLua is usually fast enough to make fps games in though.

Coming soon:

  • Beta version:
    – Bytecode support; The Editor plugin will be able to generate bytecode in your exported project rather than compile at runtime.
    – Special environment functions; Some like require, os.tick and typeof have already been implemented, but more to come!
    – Filesystem
  • After release:
    – Video & interactive tutorials
2 Likes

So I’ve found out there are not only two, but even three big libraries for running Lua in the browser with a translation layer. This means I might add all 3 backends for babyLua, and when installing you pick which of the three you want. The libraries I’m talking about:
GitHub - ceifa/wasmoon: A real lua 5.4 VM with JS bindings made with webassembly (current backend, much wasm, few JS)
GitHub - Doridian/LuaJS: Lua VM running in Javascript (using emscripten) (balanced wasm and js)
GitHub - fengari-lua/fengari: 🌙 φεγγάρι - The Lua VM written in JS ES6 for Node and the browser (100% JS)
More wasm gives you more speed, but less stability turned out not to be 100% true.

So I’ve done some research and benchmarks, and decided I will not add all 3 backends to babyLua, but instead focus on LuaJS. Percentages are compared to the best. Here are the results:

Raw speed is calling a lot of Lua functions and native syntax
Transl speed is calling a lot of JS functions from Lua
Inject speed is adding a lot of JS elements into the Lua environment

Wasmoon (WASM):
    5.4, Async
    Raw speed       40.5  100%
    Transl speed    35.4  16%
    Inject speed    59    27%
Fengari (JS):
    5.3, Sync
    Raw speed       537.1 7%
    Transl speed    13.3  42%
    Inject speed    67    24%
LuaJS (hybrid):
    5.4,  Async
    Raw speed       68.3  59%
    Transl speed    5.6   100%
    Inject speed    16    100%

The main bottlenecks in Babylon.js are:

1. Too many draw calls
Many individual meshes → high GPU overhead.

2. Heavy materials and textures
Complex PBR shaders, large or uncompressed textures slow down rendering.

3. Expensive shadows and post-processing
Shadow maps and effects like SSAO, DOF, bloom cost a lot of GPU time.

4. Large scene graphs
Thousands of objects increase CPU traversal and update costs.

5. Physics overhead
Many physics bodies or complex collision shapes consume CPU.

6. Asset size and VRAM limits
Huge GLB files or textures cause slow loading and GPU memory pressure.

have you tested the lua integration with this in mind? :slight_smile:

1 Like

Wow, I have not, in fact. At first I thought it wouldn’t be important because babyLua is only a translation layer, but now you mention it, it’s a risk that huge BabylonJS costs cause the Lua state to behave different too.

I’m currently rewriting LuaJS and Fengari to support tests decently (wasmoon already does due to how their proxy system works), you’ll hear more about the results tomorrow or the day after! :slight_smile:

1 Like

So I’ve ran some more tests and, although the tests weren’t performed well enough to actually prove anything, I can confirm that huge BabylonJS overhead doesn’t affect Wasmoon/LuaJS a lot (~10%).

My conclusion is that I’m just going to drop Fengari, and continue with Wasmoon and LuaJS. I’ll make a wrapper with shared function names for both of them and when you install babyLua you can pick which of the two you want as backend, and later you can of course migrate between them.

1 Like