Heyplay Blog

From Lua to TypeScript: Game-Changing (R)evolution for Heyplay-Powered Gamedev

Introducing the most pivotal shift in Heyplay’s journey to date. The move to TypeScript signifies a milestone filled with immediate benefits and future promises, all revealed in this post.


Wow, I can’t believe this day has come! Yes, it’s been just a couple of days since I’ve announced that work on Heyplay will pick up the pace and that some big changes are coming but don’t get fooled — the whole process leading to this breakthrough was much much longer.

But it’s here: as of today Heyplay uses TypeScript scripting powered by V8. The language that has taken the world by storm by letting JavaScript apps thrive & grow like never before, powered by same engine that Chrome uses to run the little thing called the Internet. And it’s not just any V8 — it’s a custom-tailored V8 runtime that optimizes for minimal overhead and best performance needed so badly in gamedev, with all the latest ES goodness plus a selection of web standards to allow making ambitious multiplayer games as easily as it gets.

Heyplay embraces TypeScript with amazing, seamless support across the platform to provide top-notch experience and convenience for those who just want to make a multiplayer game. And that’s all just the beginning.

Let me tell you all about it.

Immediate benefits

With me being me, I’d love to spend the remainder of this post (& more) to brag about all the technical bliss that comes with this breakthrough change and all the architectural & engineering work that enabled it. But Heyplay is first and foremost a product so let’s focus on what this means for Heyplay hackers first.

Superior scripting language

TypeScript is without a doubt one of the most popular & fastest growing languages on the planet (actually it’s the fastest growing one this year). And for a reason — it’s a substantial, widely acclaimed improvement over JavaScript. It’s also a well funded & well maintained open source effort backed by a giant like Microsoft and a thriving ecosystem of tooling.

At the same time Lua is a niche language that seems to be on the decline. From my observations it’s not a first choice anymore in modern apps with embedded scripting (which often go for… JS or JS derivatives) and game engines (which seem to rely on Lua less and less with every passing year).

This means that by relying on TypeScript, Heyplay invites millions of existing developers that already use it for all kinds of activities:

  • web development — front-end and back-end with Node.js
  • mobile app development — with React Native, Ionic or Cordova
  • desktop apps — powering top apps like Slack, Discord, VSCode, Skype etc
  • productivity apps — scripting & plugins in Office, Google, Adobe, Figma etc
  • game development — game scripting in Unity, Phaser etc
  • IoT — to program devices and sensors with Cylon, Tessel etc
  • cloud computing — top FaaS choice on Lambda, Google, Azure etc
  • AI & machine learning — model training & execution with TensorFlow.js etc
  • data visualization — complex and beautiful data visualizations with D3 etc
  • automation & testing — with Postman, Selenium, Puppeteer etc
  • VR & AR – interactive experience on the web with A-Frame, React 360 etc

The list goes on and on. It’s crazy how ever-present it is.

Now look at it from the reverse perspective — every scripting newbie willing to take up the challenge of making games with Heyplay will be learning TS/JS along the way, getting ready to dive into all these industries next. What a great prospect, so fitting the Heyplay mission!

When it comes to syntax and language features, TS/JS may not be perfect but it has improved with recent ES updates and from my perspective it’s a pretty “normal” high-level language compared to following Lua problems:

  • need for boilerplate code or 3rd party libs for defining a class
  • lack of baked-in string interpolation — get used to "Hi " .. name .. "!"
  • ~= operator for “not equal” — no it’s not a string match… speaking of which…
  • quirky regex support — it’s a far cry from the /.../ syntax

Last but not least, the runtime. V8 — used by Chrome, NodeJS and now Heyplay — is one of best funded & supported runtimes out there (backed by Google). OTOH Lua is stagnating — the widely acclaimed LuaJIT is x86-only & inactive, standard Lua is widely… rejected and Luau is a young & proprietary novelty.

Improved code editing experience

It starts with typing. TypeScript has it in its name & in its DNA. It helps in keeping the code clean and understandable, allowing to dodge sneaky bugs before they ruin the game. Plus, the extra help from context-aware autocompletion in the editor makes navigating through available APIs feel like a breeze. This should help making bigger & better games — faster and with fewer headaches.

Lua’s best shot at typing is Roblox’s Luau that’s very young, semi-prioprietory and driven by single company’s needs. It’s a long shot at bringing at least a glimpse of TS to the huge Lua codebase that Roblox must cope with.

Then there’s the topic of documentation. TypeScript uses a battle-proven JSDoc format that lives & evolves with the code and that Heyplay can just pull into help pages while Lua’s equivalents lack in terms of recognition and tooling — which resulted in Heyplay managing docs for all APIs in separation from the code, increasing the effort and resulting in inconsistencies more than once.

Heyplay benefits from both typing and docs via TypeScript worker in Monaco. This enables client-side syntax checking, type validation, code completion (a.k.a. IntelliSense) and docs powered by a real import-enabled TS compiler. In addition, Heyplay API docs are generated straight from their code now. ✨

Vast ecosystem of libraries

NPM provides a vast ecosystem of libraries, while LuaRocks looks embarrassing compared. When it comes to plain package count it’s ~2.5M vs ~3.5K - yup, Lua loses by almost a thousand times! 🤯

But hey hey, NPM surely holds tons of stuff that’s useless for gamedev while Lua has always been out there in gaming right? After all, they say that numbers never lie, but liars always use numbers, right?

OK, so let’s see what 2D physics libs are out there — something that I really needed to support collisions between sth other than circles (one of top needed features for Heyplay). LuaRocks gives me bump.lua with AABB-only support and last commit from… 4 years ago. Outside of LuaRocks, I’ve also found HC which turned out to be… no longer maintained and Box2d bindings but… only for Defold and LÖVE engines. Boring, dusty, abandoned or hardcoded…

NPM OTOH? OMG, where do I start: Matter.js (lean & clean), Box2d (available as JS rewrite, Emscripten build, WASM…), ammo.js (almighty Bullet in JS), Rapier (promising new contender in Rust/WASM). It’s all out there & more.

Also, what exactly is that part of NPM that’d be “useless for gamedev”? Gamedev involves almost every kind of problem solving — duh, that’s why it’s so cool! It can obviously use libs for math, 3D, audio, ECS, pathfinding, message packing but also charts for sci-fi visuals, AI for role-play, or just one of 5 million front-end frameworks for a more ambitious UI. Trust me, nothing will go to waste.


Heyplay IOKit library (which is the equivalent of the old Heyplay Engine API in Lua) has already benefitted from this opportunity by switching to more mature physics and message packing libraries. The initial added value from the former is the empowered collision & physics system.

Future promises

Aside from immediate benefits, TypeScript is a huge enabler for the Heyplay’s future endevours — most of these are main pain points of early adopters that I’ve mentioned about in the previous post.

First off, Heyplay engine may now be extended with all the goodness from NPM. As mentioned, it has already switched to a proper physics lib but has barely scratched the surface of what’s possible with it (in order to do things iteratively). It shouldn’t take much to introduce different physical shapes or behaviours. It’s gonna be a challenge to keep things simple but we’ll surely find a way.

TS & V8 combo offers the import feature to enable working with multiple files. It may be made to work the same on the client, on the server and in the editor. This is gonna be a great feature on its own for larger & more ambitious games and for sharing of common code, but it’s also an enabler for the biggest goal…

Many flexibility issues come down to fixed & hardcoded client. That’s why Heyplay needs to allow editing client-side scripts. With TS/JS on the server as well, Heyplay author could use the same language everywhere, while sharing common parts between client and server (a.k.a. isomorphism!). This enables a wide selection of features from simple ones like customizable renderer, UI, inputs etc, to sophisticated ones like optimistic updates backed by server-side cheat-proof validation or offloading of non-critical parts of the logic to the client.

These future goals clearly show how big of a deal the Lua-TS switchover is and how it raises the bar of what’s possible for Heyplay now.

Migration

All existing user games will have to be converted from Lua to TypeScript. Thanks to the similar API, the process is actually simpler that it may sound and may be aided by AI to a large extent. Please reach me if needed and I’ll do my best to help you get through the transition.

Be sure to check out the revamped editor documentation and especially the page about scripting language & runtime capabilities which explains in greater detail what is and what isn’t possible in the scripts.

With this release Heyplay also drops visual editor based on Blockly. It’s not like it couldn’t work because it’s actually easier to set up Blockly to generate JS than to generate Lua. It’s more a feeling that the way it was approached in Heyplay wouldn’t scale for all the changes that come (or are planned to come) together with the switchover to TypeScript - multi-file projects, type-aware scripting, client-side scripting. Visual scripting may come back but it’ll have to be seriously bumped up to meet the bar raised by TypeScript. Let me know if you need it.

Deno is the key

The switchover from Lua to TypeScript + V8 in Heyplay wouldn’t be possible without the efforts of the Deno team. Deno is an amazing project that offers a modern, unified and standard-driven scripting experience on the server-side. There are multiple factors that make Deno a great foundation for Heyplay:

  • it allows to build a custom JavaScript runtime
  • it’s secure by default (great for running user game scripts in the cloud)
  • it’s consistent with browser APIs (which fits isomorphic gamedev perfectly)
  • it allows to hand-pick parts of Web Standards (great for performance)
  • it transpiles, runs & generates docs for TypeScript out of the box
  • it’s built in Rust (so it’s fast and Heyplay’s Elixir core can call into it)

Thank you, Deno team! I hope Heyplay will serve as yet another proof of & example for how spot-on the Deno’s promise is.

Summary

Switching the execution runtime was like a heart transplantation for Heyplay, so obviosuly it took a lot of thinking, pros vs cons consideration, reading, open source parsing, planning, benchmarking, case-by-case examination… And then the migration itself which touched almost every part of the app. Phew! 😅

But I’m really happy for this change because it’s a perfect time for it. TypeScript will help in solving all the pain points reported by early adopters and Heyplay still hasn’t grown too much to make such a big change too painful. The technology itself is also thriving: the performance bar is being raised higher than ever by projects like Deno or Bun and import with plain ES modules that Heyplay relies on becomes a reality both in browsers and server-side runtimes.

As always, feel invited to the Heyplay server on Discord to share your thoughts.